From: Tony Tkacik Date: Wed, 18 Dec 2013 13:59:11 +0000 (+0100) Subject: Fixed Bug 250 - bits serialization between Binding Broker and DOM broker X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~169^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=d2f7cb631a1261018315f8fe1575d6c506eea13a Fixed Bug 250 - bits serialization between Binding Broker and DOM broker - fixed serialization bug for YANG bits type when crossing brokers - Added regression test for bug, based on provided bug report - Decreased log level to debug and trace for some code generation functionality. Change-Id: I07982bb7ffefb4350ec4922c02207eb4dc368ab8 Signed-off-by: Tony Tkacik --- diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend index 7ebcf02e41..8b41552857 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend @@ -71,7 +71,7 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co body = ''' { if(«DELEGATE_FIELD» == null) { - throw new java.lang.IllegalStateException("No provider is processing supplied message"); + throw new java.lang.IllegalStateException("No default provider is available"); } return ($r) «DELEGATE_FIELD».«it.name»($$); } @@ -127,7 +127,7 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co instance = «DELEGATE_FIELD»; } if(instance == null) { - throw new java.lang.IllegalStateException("No provider is processing supplied message"); + throw new java.lang.IllegalStateException("No routable provider is processing routed message for " + String.valueOf(identifier)); } return ($r) instance.«it.name»($$); }''' diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java index 8309651446..588bc789cf 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java @@ -1,7 +1,11 @@ package org.opendaylight.controller.sal.binding.codegen.impl; +import java.util.List; + import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; public class XtendHelper { @@ -9,4 +13,9 @@ public class XtendHelper { Class cls) { return new RpcRoutingTableImpl<>(cls); } + + @SuppressWarnings({"rawtypes","unchecked"}) + public static Iterable getTypes(UnionTypeDefinition definition) { + return (Iterable) (List) definition.getTypes(); + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java index f1ba5843ba..cabb1bc4e2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java @@ -233,7 +233,7 @@ public class LazyGeneratedCodecRegistry implements // if (typeToClass.containsKey(typeRef)) { return; } - LOG.info("Binding Class {} encountered.", cls); + LOG.trace("Binding Class {} encountered.", cls); WeakReference weakRef = new WeakReference<>(cls); typeToClass.put(typeRef, weakRef); if (Augmentation.class.isAssignableFrom(cls)) { @@ -250,7 +250,7 @@ public class LazyGeneratedCodecRegistry implements // if (typeToClass.containsKey(typeRef)) { return; } - LOG.info("Binding Class {} encountered.", cls); + LOG.trace("Binding Class {} encountered.", cls); WeakReference weakRef = new WeakReference<>((Class) cls); typeToClass.put(typeRef, weakRef); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend index 4271ef9c1a..e5bd3e7b9a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend @@ -56,6 +56,14 @@ import javassist.CannotCompileException import java.util.concurrent.locks.Lock import java.util.concurrent.Callable import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils +import org.opendaylight.yangtools.yang.model.api.TypeDefinition +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition +import java.util.HashSet +import java.util.Collections +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit +import java.util.Set +import org.opendaylight.controller.sal.binding.codegen.impl.XtendHelper class TransformerGenerator { @@ -243,19 +251,24 @@ class TransformerGenerator { transformerFor(cls, node); } - private def Class getValueSerializer(GeneratedTransferObject type) { + private def Class valueSerializer(GeneratedTransferObject type, TypeDefinition typeDefinition) { val cls = loadClassWithTCCL(type.resolvedName); val transformer = cls.generatedClass; if (transformer !== null) { return transformer; } + var baseType = typeDefinition; + while (baseType.baseType != null) { + baseType = baseType.baseType; + } + val finalType = baseType; return withClassLoaderAndLock(cls.classLoader, lock) [ | - val valueTransformer = generateValueTransformer(cls, type); + val valueTransformer = generateValueTransformer(cls, type, finalType); return valueTransformer; ] } - private def Class getValueSerializer(Enumeration type) { + private def Class valueSerializer(Enumeration type, TypeDefinition typeDefinition) { val cls = loadClassWithTCCL(type.resolvedName); val transformer = cls.generatedClass; if (transformer !== null) { @@ -340,7 +353,7 @@ class TransformerGenerator { ] ] val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret as Class, ?>>; } catch (Exception e) { processException(inputType, e); @@ -391,7 +404,7 @@ class TransformerGenerator { method(Object, "deserialize", Object) [ bodyChecked = ''' { - //System.out.println("«type.name»#deserialize: " +$1); + ////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()); } @@ -401,7 +414,7 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class> listener?.onDataContainerCodecCreated(inputType, ret); - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret; } catch (Exception e) { processException(inputType, e); @@ -450,7 +463,7 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class, Object>> listener?.onDataContainerCodecCreated(inputType, ret); - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret; } catch (Exception e) { processException(inputType, e); @@ -475,14 +488,14 @@ class TransformerGenerator { modifiers = PUBLIC + FINAL + STATIC bodyChecked = ''' { - //System.out.println("Qname " + $1); - //System.out.println("Value " + $2); + ////System.out.println("Qname " + $1); + ////System.out.println("Value " + $2); «QName.name» _resultName = «QName.name».create(QNAME,QNAME.getLocalName()); java.util.List _childNodes = new java.util.ArrayList(); «type.resolvedName» value = («type.resolvedName») $2; «FOR child : node.childNodes» «var signature = properties.getFor(child)» - //System.out.println("«signature.key»" + value.«signature.key»()); + ////System.out.println("«signature.key»" + value.«signature.key»()); «serializeProperty(child, signature.value, signature.key)» «ENDFOR» return ($r) _childNodes; @@ -511,7 +524,7 @@ class TransformerGenerator { return null; } java.util.Map _compositeNode = (java.util.Map) $2; - //System.out.println(_localQName + " " + _compositeNode); + ////System.out.println(_localQName + " " + _compositeNode); «type.builderName» _builder = new «type.builderName»(); boolean _is_empty = true; «FOR child : node.childNodes» @@ -571,7 +584,7 @@ class TransformerGenerator { } java.util.Map.Entry _input = new «SimpleEntry.name»($1,_baValue); Object _ret = _codec.serialize(_input); - //System.out.println("«typeSpec.name»#toDomStatic: " + _ret); + ////System.out.println("«typeSpec.name»#toDomStatic: " + _ret); return («List.name») _ret; } ''' @@ -603,7 +616,7 @@ class TransformerGenerator { val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) val ret = rawRet as Class, Object>>; listener?.onChoiceCodecCreated(inputType, ret, node); - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret; } catch (Exception e) { processException(inputType, e); @@ -689,7 +702,7 @@ class TransformerGenerator { return null; } java.util.Map _compositeNode = (java.util.Map) $2; - //System.out.println(_localQName + " " + _compositeNode); + ////System.out.println(_localQName + " " + _compositeNode); «type.builderName» _builder = new «type.builderName»(); «deserializeDataNodeContainerBody(type, node)» «deserializeAugmentations» @@ -722,7 +735,7 @@ class TransformerGenerator { «Iterator.name» _entries = _augmentation.entrySet().iterator(); while(_entries.hasNext()) { java.util.Map.Entry _entry = (java.util.Map.Entry) _entries.next(); - //System.out.println("Aug. key:" + _entry.getKey()); + ////System.out.println("Aug. key:" + _entry.getKey()); Class _type = (Class) _entry.getKey(); «Augmentation.resolvedName» _value = («Augmentation.name») _entry.getValue(); if(_value != null) { @@ -736,7 +749,7 @@ class TransformerGenerator { String propertyName) ''' java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName. localName»")); - //System.out.println("«propertyName»#deCode"+_dom_«propertyName»); + ////System.out.println("«propertyName»#deCode"+_dom_«propertyName»); java.util.List «propertyName» = new java.util.ArrayList(); if(_dom_«propertyName» != null) { java.util.List _serialized = new java.util.ArrayList(); @@ -745,15 +758,15 @@ class TransformerGenerator { while(_hasNext) { Object _listItem = _iterator.next(); _is_empty = false; - //System.out.println(" item" + _listItem); + ////System.out.println(" item" + _listItem); Object _value = «type.actualTypeArguments.get(0).serializer(schema).resolvedName».fromDomStatic(_localQName,_listItem); - //System.out.println(" value" + _value); + ////System.out.println(" value" + _value); «propertyName».add(_value); _hasNext = _iterator.hasNext(); } } - //System.out.println(" list" + «propertyName»); + ////System.out.println(" list" + «propertyName»); ''' private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type, @@ -770,7 +783,7 @@ class TransformerGenerator { Object _listItem = _iterator.next(); if(_listItem instanceof java.util.Map.Entry) { Object _innerValue = ((java.util.Map.Entry) _listItem).getValue(); - Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue")»; + Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue", schema.type)»; «propertyName».add(_value); } _hasNext = _iterator.hasNext(); @@ -786,7 +799,7 @@ class TransformerGenerator { _is_empty = false; java.util.Map.Entry _dom_«propertyName» = (java.util.Map.Entry) _dom_«propertyName»_list.get(0); Object _inner_value = _dom_«propertyName».getValue(); - «propertyName» = «deserializeValue(type, "_inner_value")»; + «propertyName» = «deserializeValue(type, "_inner_value", schema.type)»; } ''' @@ -809,16 +822,17 @@ class TransformerGenerator { } ''' - private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter) ''' - («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter») + private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter, + TypeDefinition typeDefinition) ''' + («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter») ''' - private def dispatch String deserializeValue(Enumeration type, String domParameter) ''' - («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter») + private def dispatch String deserializeValue(Enumeration type, String domParameter, TypeDefinition typeDefinition) ''' + («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter») ''' private def dispatch Class, Object>> generateValueTransformer( - Class inputType, GeneratedTransferObject typeSpec) { + Class inputType, GeneratedTransferObject typeSpec, TypeDefinition typeDef) { try { val returnType = typeSpec.valueReturnType; @@ -827,11 +841,6 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) return ret as Class, Object>>; } - if (returnType.name == 'char[]') { - val ctCls = createUnionImplementation(inputType, typeSpec); - val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - return ret as Class, Object>>; - } val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); @@ -846,16 +855,16 @@ class TransformerGenerator { val ctSpec = typeSpec.asCtClass; bodyChecked = ''' { - //System.out.println("«inputType.simpleName»#toDomValue: "+$1); + ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); if($1 == null) { return null; } «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1; - //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); + ////System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); «returnType.resolvedName» _value = _encapsulatedValue.getValue(); - //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value); - Object _domValue = «serializeValue(returnType, "_value")»; + ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value); + Object _domValue = «serializeValue(returnType, "_value", null)»; return _domValue; } ''' @@ -871,12 +880,12 @@ class TransformerGenerator { modifiers = PUBLIC + FINAL + STATIC bodyChecked = ''' { - //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1); if($1 == null) { return null; } - «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1")»; + «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1", null)»; «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(_simpleValue); return _value; } @@ -891,7 +900,7 @@ class TransformerGenerator { ] val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret as Class, Object>>; } catch (Exception e) { log.error("Cannot compile DOM Codec for {}", inputType, e); @@ -899,74 +908,182 @@ class TransformerGenerator { exception.addSuppressed(e); throw exception; } - } - def createUnionImplementation(Class inputType, GeneratedTransferObject typeSpec) { - return createClass(typeSpec.codecClassName) [ - val properties = typeSpec.allProperties; - //staticField(Map,"AUGMENTATION_SERIALIZERS"); - if (inputType.isYangBindingAvailable) { - implementsType(BINDING_CODEC) - staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) - staticField(it, IDENTITYREF_CODEC, BindingCodec) - implementsType(BindingDeserializer.asCtClass) - } - method(Object, "toDomValue", Object) [ - modifiers = PUBLIC + FINAL + STATIC - val ctSpec = inputType.asCtClass; - bodyChecked = ''' - { - //System.out.println("«inputType.simpleName»#toDomValue: "+$1); - - if($1 == null) { + private def dispatch Class, Object>> generateValueTransformer( + Class inputType, GeneratedTransferObject typeSpec, UnionTypeDefinition typeDef) { + try { + 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) + implementsType(BindingDeserializer.asCtClass) + } + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val ctSpec = inputType.asCtClass; + + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); + + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1; + «FOR property : properties.entrySet» + «IF property.key != "getValue"» + «property.value.resolvedName» «property.key» = («property.value.resolvedName») _value.«property. + key»(); + if(«property.key» != null) { + return «serializeValue(property.value, property.key, getterToTypeDefinition.get(property.key))»; + } + «ENDIF» + «ENDFOR» + return null; } - «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1; - «FOR property : properties.entrySet» - «IF property.key != "getValue"» - «property.value.resolvedName» «property.key» = («property.value.resolvedName») _value.«property.key»(); - if(«property.key» != null) { - return «serializeValue(property.value, property.key)»; - } - «ENDIF» - «ENDFOR» - - return null; - } - ''' - ] - method(Object, "serialize", Object) [ - bodyChecked = ''' - { - return toDomValue($1); - } - ''' - ] - method(Object, "fromDomValue", Object) [ - modifiers = PUBLIC + FINAL + STATIC - bodyChecked = ''' - { - //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); - - if($1 == null) { - return null; + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + return toDomValue($1); } - if($1 instanceof String) { - String _simpleValue = (String) $1; - return new «typeSpec.resolvedName»(_simpleValue.toCharArray()); + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + + if($1 == null) { + return null; + } + if($1 instanceof String) { + String _simpleValue = (String) $1; + return new «typeSpec.resolvedName»(_simpleValue.toCharArray()); + } + return null; } - return null; + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = '''{ + return fromDomValue($1); } - ''' + ''' + ] ] - method(Object, "deserialize", Object) [ - bodyChecked = '''{ + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret as Class, Object>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}", inputType, e); + val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + } + + + private def dispatch Class, Object>> generateValueTransformer( + Class inputType, GeneratedTransferObject typeSpec, BitsTypeDefinition typeDef) { + try { + 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) + implementsType(BindingDeserializer.asCtClass) + } + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val ctSpec = typeSpec.asCtClass; + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); + + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1; + «HashSet.resolvedName» _value = new «HashSet.resolvedName»(); + //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); + + «FOR bit : typeDef.bits» + «val getter = bit.getterName()» + if(Boolean.TRUE.equals(_encapsulatedValue.«getter»())) { + _value.add("«bit.name»"); + } + «ENDFOR» + «Set.resolvedName» _domValue = «Collections.resolvedName».unmodifiableSet(_value); + //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_domValue); + + return _domValue; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + return toDomValue($1); + } + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val sortedBits = typeDef.bits.sort[o1, o2|o1.propertyName.compareTo(o2.propertyName)] + bodyChecked = ''' + { + //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + + if($1 == null) { + return null; + } + «Set.resolvedName» _domValue = («Set.resolvedName») $1; + «FOR bit : sortedBits» + Boolean «bit.propertyName» = Boolean.valueOf(_domValue.contains("«bit.name»")); + «ENDFOR» + + return new «inputType.resolvedName»(«FOR bit : sortedBits SEPARATOR ","»«bit.propertyName»«ENDFOR»); + } + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = '''{ return fromDomValue($1); } ''' + ] ] - ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret as Class, Object>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}", inputType, e); + val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + } + + def String getPropertyName(Bit bit) { + '''_«BindingGeneratorUtil.parseToValidParamName(bit.name)»''' + } + + def String getterName(Bit bit) { + + val paramName = BindingGeneratorUtil.parseToValidParamName(bit.name); + return '''is«paramName.toFirstUpper»'''; } def boolean isYangBindingAvailable(Class class1) { @@ -1030,7 +1147,7 @@ class TransformerGenerator { return null; } - private def dispatch Class generateValueTransformer(Class inputType, Enumeration typeSpec) { + private def Class generateValueTransformer(Class inputType, Enumeration typeSpec) { try { val typeRef = new ReferencedTypeImpl(typeSpec.packageName, typeSpec.name); val schema = typeToSchemaNode.get(typeRef) as ExtendedType; @@ -1086,7 +1203,7 @@ class TransformerGenerator { ] val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret; } catch (CodeGenerationException e) { throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e); @@ -1116,7 +1233,7 @@ class TransformerGenerator { } - private def dispatch String deserializeValue(Type type, String domParameter) { + private def dispatch String deserializeValue(Type type, String domParameter, TypeDefinition typeDef) { if (INSTANCE_IDENTIFIER.equals(type)) { return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)''' } else if (CLASS_TYPE.equals(type)) { @@ -1214,7 +1331,7 @@ class TransformerGenerator { «FOR child : node.childNodes» «val signature = properties.getFor(child)» «IF signature !== null» - //System.out.println("«type.name»#«signature.key»" + value.«signature.key»()); + ////System.out.println("«type.name»#«signature.key»" + value.«signature.key»()); «serializeProperty(child, signature.value, signature.key)» «ENDIF» «ENDFOR» @@ -1256,7 +1373,7 @@ class TransformerGenerator { private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type, String propertyName) ''' «type.resolvedName» «propertyName» = value.«propertyName»(); - //System.out.println("«propertyName»:" + «propertyName»); + ////System.out.println("«propertyName»:" + «propertyName»); if(«propertyName» != null) { java.util.Iterator _iterator = «propertyName».iterator(); boolean _hasNext = _iterator.hasNext(); @@ -1274,7 +1391,7 @@ class TransformerGenerator { if(«propertyName» != null) { «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»"); - Object _propValue = «serializeValue(type, propertyName)»; + Object _propValue = «serializeValue(type, propertyName, schema.type)»; if(_propValue != null) { Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); _childNodes.add(_domValue); @@ -1282,12 +1399,15 @@ class TransformerGenerator { } ''' - private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer. - resolvedName».toDomValue(«parameter»)''' + private def dispatch serializeValue(GeneratedTransferObject type, String parameter, TypeDefinition typeDefinition) { + '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)''' + } - private def dispatch serializeValue(Enumeration type, String parameter) '''«type.valueSerializer.resolvedName».toDomValue(«parameter»)''' + private def dispatch serializeValue(Enumeration type, String parameter, TypeDefinition typeDefinition) { + '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)''' + } - private def dispatch serializeValue(Type signature, String property) { + private def dispatch serializeValue(Type signature, String property, TypeDefinition typeDefinition) { if (INSTANCE_IDENTIFIER == signature) { return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)''' } else if (CLASS_TYPE.equals(signature)) { @@ -1308,7 +1428,7 @@ class TransformerGenerator { boolean _hasNext = _iterator.hasNext(); while(_hasNext) { Object _listItem = _iterator.next(); - Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem")»; + Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem", schema.type)»; Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); _childNodes.add(_domValue); _hasNext = _iterator.hasNext(); diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/FlagsSerializationTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/FlagsSerializationTest.java new file mode 100644 index 0000000000..1304f0d52a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/FlagsSerializationTest.java @@ -0,0 +1,210 @@ +package org.opendaylight.controller.sal.binding.test.bugfix; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + + + + + + + + + + + + + + + + + + + +import org.junit.Test; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.mpls.action._case.PopMplsActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +import static org.junit.Assert.*; + +public class FlagsSerializationTest extends AbstractDataServiceTest { + + private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); + private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id"); + private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node"); + private static final long FLOW_ID = 1234; + private static final short TABLE_ID = (short)0; + private static final String NODE_ID = "node:1"; + + private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); + private static final FlowKey FLOW_KEY = new FlowKey(new FlowId(FLOW_ID)); + private static final TableKey TABLE_KEY = new TableKey(TABLE_ID); + + private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, + NODE_ID); + + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // + .child(Node.class, NODE_KEY).toInstance(); + + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = // + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // + .node(Nodes.QNAME) // + .nodeWithKey(Node.QNAME, NODE_KEY_BI) // + .toInstance(); + private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA); + + + +// private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier FLOW_INSTANCE_ID_BI = // +// org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // +// +// .node(Flows.QNAME) // +// .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) // +// .toInstance(); + private static final InstanceIdentifier FLOW_INSTANCE_ID_BA = // + InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) // + .augmentation(FlowCapableNode.class) + .child(Table.class,TABLE_KEY) + .child(Flow.class, FLOW_KEY) // + .toInstance(); + private static final QName FLOW_FLAGS_QNAME = QName.create(Flow.QNAME, "flags"); + + @Test + public void testIndirectGeneration() throws Exception { + + FlowModFlags checkOverlapFlags = new FlowModFlags(true,false,false,false,false); + ImmutableSet domCheckOverlapFlags = ImmutableSet.of("CHECK_OVERLAP"); + testFlags(checkOverlapFlags,domCheckOverlapFlags); + + + + FlowModFlags allFalseFlags = new FlowModFlags(false,false,false,false,false); + ImmutableSet domAllFalseFlags = ImmutableSet.of(); + testFlags(allFalseFlags,domAllFalseFlags); + + FlowModFlags allTrueFlags = new FlowModFlags(true,true,true,true,true); + ImmutableSet domAllTrueFlags = ImmutableSet.of("CHECK_OVERLAP","NO_BYT_COUNTS", "NO_PKT_COUNTS", "RESET_COUNTS", "SEND_FLOW_REM"); + testFlags(allTrueFlags,domAllTrueFlags); + + FlowModFlags nullFlags = null; + ImmutableSet domNullFlags = null; + testFlags(null,null); + + + + } + + private void testFlags(FlowModFlags flagsToTest, ImmutableSet domFlags) throws Exception { + Flow flow = createFlow(flagsToTest); + assertNotNull(flow); + + CompositeNode domFlow = biDataService.readConfigurationData(mappingService.toDataDom(FLOW_INSTANCE_ID_BA)); + + assertNotNull(domFlow); + org.opendaylight.yangtools.yang.data.api.Node readedFlags = domFlow.getFirstSimpleByName(FLOW_FLAGS_QNAME); + + if(domFlags != null) { + assertNotNull(readedFlags); + assertEquals(domFlags,readedFlags.getValue()); + } else { + assertNull(readedFlags); + } + assertEquals(flagsToTest, flow.getFlags()); + + DataModificationTransaction transaction = baDataService.beginTransaction(); + transaction.removeConfigurationData(FLOW_INSTANCE_ID_BA); + RpcResult result = transaction.commit().get(); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + + } + + private Flow createFlow(FlowModFlags flagsToTest) throws Exception { + + DataModificationTransaction modification = baDataService.beginTransaction(); + + FlowBuilder flow = new FlowBuilder(); + MatchBuilder match = new MatchBuilder(); + VlanMatchBuilder vlanBuilder = new VlanMatchBuilder(); + VlanIdBuilder vlanIdBuilder = new VlanIdBuilder(); + VlanId vlanId = new VlanId(10); + vlanBuilder.setVlanId(vlanIdBuilder.setVlanId(vlanId).build()); + match.setVlanMatch(vlanBuilder.build()); + + flow.setKey(FLOW_KEY); + flow.setMatch(match.build()); + + flow.setFlags(flagsToTest); + + InstructionsBuilder instructions = new InstructionsBuilder(); + InstructionBuilder instruction = new InstructionBuilder(); + + instruction.setOrder(10); + ApplyActionsBuilder applyActions = new ApplyActionsBuilder(); + List actionList = new ArrayList<>(); + PopMplsActionBuilder popMplsAction = new PopMplsActionBuilder(); + popMplsAction.setEthernetType(34); + actionList.add(new ActionBuilder().setAction(new PopMplsActionCaseBuilder().setPopMplsAction(popMplsAction.build()).build()).setOrder(10).build()); + + applyActions.setAction(actionList ); + + instruction.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions.build()).build()); + + + List instructionList = Collections.singletonList(instruction.build()); + instructions.setInstruction(instructionList ); + + flow.setInstructions(instructions.build()); + modification.putConfigurationData(FLOW_INSTANCE_ID_BA, flow.build()); + RpcResult ret = modification.commit().get(); + assertNotNull(ret); + assertEquals(TransactionStatus.COMMITED, ret.getResult()); + return (Flow) baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA); + } +}