From 81a6e2e3fc28063a043ef14aabdd68d7ccab85b2 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Wed, 13 Nov 2013 16:40:24 +0100 Subject: [PATCH] Fixed performance issues with implementation of BA-to-BI mapping Codecs are lazily created on first need when traversing boundatories between brokers Change-Id: I72967babd613ecbc3c9f8f7bd04a4b938f7c0086 Signed-off-by: Tony Tkacik --- .../md-sal/sal-binding-broker/pom.xml | 1 + .../binding/codegen/RuntimeCodeGenerator.java | 2 - .../binding/codegen/impl/JavassistUtils.java | 27 - .../codegen/impl/RuntimeCodeGenerator.xtend | 73 +- .../binding/codegen/util/ClassGenerator.java | 7 + .../binding/codegen/util/FieldGenerator.java | 7 + .../binding/codegen/util/JavassistUtils.xtend | 94 +++ .../binding/codegen/util/MethodGenerator.java | 7 + .../impl/TransformerGenerator.xtend | 776 ++++++++++++++++++ .../impl/connect/dom/BindingMapping.xtend | 100 ++- .../impl/connect/dom/CompositeNodeUtils.java | 5 + .../impl/connect/dom/ConnectorActivator.java | 11 +- .../RuntimeGeneratedMappingServiceImpl.xtend | 235 ++++++ .../binding/impl/util/ClassLoaderUtils.java | 7 +- .../connect/dom/BrokerIntegrationTest.java | 61 +- 15 files changed, 1276 insertions(+), 137 deletions(-) delete mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/ClassGenerator.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/FieldGenerator.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/JavassistUtils.xtend create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/MethodGenerator.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/CompositeNodeUtils.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index 35264e74e6..9e4d3a580c 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -88,6 +88,7 @@ org.opendaylight.controller.sal.binding.impl.*, org.opendaylight.controller.sal.binding.codegen, org.opendaylight.controller.sal.binding.codegen.*, + org.opendaylight.controller.sal.binding.dom.*, diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java index 1d828077b8..6672d953a2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java @@ -7,11 +7,9 @@ */ package org.opendaylight.controller.sal.binding.codegen; -import org.opendaylight.controller.sal.binding.spi.DelegateProxy; import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; import org.opendaylight.controller.sal.binding.spi.RpcRouter; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.RpcImplementation; import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext; diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java deleted file mode 100644 index c6be284f4c..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.binding.codegen.impl; - -import javassist.CtClass; -import javassist.CtField; -import javassist.CtMethod; - -public class JavassistUtils { - - public static interface ClassGenerator { - void process(CtClass cls); - } - - public static interface MethodGenerator { - void process(CtMethod method); - } - - public static interface FieldGenerator { - void process(CtField field); - } -} 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 ea6dc131c6..93c192c0af 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 @@ -12,9 +12,6 @@ import org.opendaylight.yangtools.yang.binding.RpcService import javassist.CtClass import static com.google.common.base.Preconditions.* - -import javassist.CtField -import javassist.Modifier import javassist.CtMethod import org.opendaylight.yangtools.yang.binding.InstanceIdentifier import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext @@ -22,13 +19,11 @@ import org.opendaylight.yangtools.yang.binding.BaseIdentity import java.util.Map import java.util.HashMap -import javassist.NotFoundException -import javassist.LoaderClassPath -import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.MethodGenerator -import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.ClassGenerator + + import org.opendaylight.yangtools.yang.binding.NotificationListener import org.opendaylight.yangtools.yang.binding.Notification -import java.util.Arrays + import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.* import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.* @@ -39,19 +34,21 @@ import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.No import java.util.Set import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper import java.util.WeakHashMap -import javassist.ClassClassPath import org.opendaylight.yangtools.yang.binding.annotations.QName import org.opendaylight.yangtools.yang.binding.DataContainer import org.opendaylight.yangtools.yang.binding.RpcImplementation +import org.opendaylight.controller.sal.binding.codegen.util.JavassistUtils class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory { val CtClass BROKER_NOTIFICATION_LISTENER; val ClassPool classPool; + val extension JavassistUtils utils; val Map, RuntimeGeneratedInvokerPrototype> invokerClasses; public new(ClassPool pool) { classPool = pool; + utils = new JavassistUtils(pool); invokerClasses = new WeakHashMap(); BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass; } @@ -216,65 +213,9 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co finalClass as Class); } - private def void method(CtClass it, Class returnType, String name, Class parameter, MethodGenerator function1) { - val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it); - function1.process(method); - it.addMethod(method); - } - - private def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) { - for (method : source.methods) { - if (method.declaringClass == source) { - val redeclaredMethod = new CtMethod(method, target, null); - function1.process(redeclaredMethod); - target.addMethod(redeclaredMethod); - } - } - } - - private def CtClass createClass(String fqn, ClassGenerator cls) { - val target = classPool.makeClass(fqn); - cls.process(target); - return target; - } - - private def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) { - val target = classPool.makeClass(fqn); - target.implementsType(superInterface); - cls.process(target); - return target; - } - - private def void implementsType(CtClass it, CtClass supertype) { - checkArgument(supertype.interface, "Supertype must be interface"); - addInterface(supertype); - } - - private def asCtClass(Class class1) { - classPool.get(class1); - } + - private def CtField field(CtClass it, String name, Class returnValue) { - val field = new CtField(returnValue.asCtClass, name, it); - field.modifiers = Modifier.PUBLIC - addField(field); - return field; - } - def get(ClassPool pool, Class cls) { - try { - return pool.get(cls.name) - } catch (NotFoundException e) { - pool.appendClassPath(new LoaderClassPath(cls.classLoader)); - try { - return pool.get(cls.name) - - } catch (NotFoundException ef) { - pool.appendClassPath(new ClassClassPath(cls)); - return pool.get(cls.name) - } - } - } protected def resolveInvokerClass(Class class1) { val invoker = invokerClasses.get(class1); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/ClassGenerator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/ClassGenerator.java new file mode 100644 index 0000000000..c4abc32e16 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/ClassGenerator.java @@ -0,0 +1,7 @@ +package org.opendaylight.controller.sal.binding.codegen.util; + +import javassist.CtClass; + +public interface ClassGenerator { + void process(CtClass cls); +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/FieldGenerator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/FieldGenerator.java new file mode 100644 index 0000000000..2e053f00e4 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/FieldGenerator.java @@ -0,0 +1,7 @@ +package org.opendaylight.controller.sal.binding.codegen.util; + +import javassist.CtField; + +public interface FieldGenerator { + void process(CtField field); +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/JavassistUtils.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/JavassistUtils.xtend new file mode 100644 index 0000000000..19737b83c6 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/JavassistUtils.xtend @@ -0,0 +1,94 @@ +package org.opendaylight.controller.sal.binding.codegen.util + +import javassist.CtClass +import javassist.CtMethod +import javassist.ClassPool +import java.util.Arrays +import static com.google.common.base.Preconditions.*; +import javassist.CtField +import javassist.Modifier +import javassist.NotFoundException +import javassist.LoaderClassPath +import javassist.ClassClassPath + +class JavassistUtils { + + ClassPool classPool + + new(ClassPool pool) { + classPool = pool; + } + + def void method(CtClass it, Class returnType, String name, Class parameter, MethodGenerator function1) { + val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it); + function1.process(method); + it.addMethod(method); + } + + def void method(CtClass it, Class returnType, String name, Class parameter1, Class parameter2, MethodGenerator function1) { + val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter1.asCtClass,parameter2.asCtClass), it); + function1.process(method); + it.addMethod(method); + } + + + def void staticMethod(CtClass it, Class returnType, String name, Class parameter, MethodGenerator function1) { + val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it); + function1.process(method); + it.addMethod(method); + } + + def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) { + for (method : source.methods) { + if (method.declaringClass == source) { + val redeclaredMethod = new CtMethod(method, target, null); + function1.process(redeclaredMethod); + target.addMethod(redeclaredMethod); + } + } + } + + def CtClass createClass(String fqn, ClassGenerator cls) { + val target = classPool.makeClass(fqn); + cls.process(target); + return target; + } + + def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) { + val target = classPool.makeClass(fqn); + target.implementsType(superInterface); + cls.process(target); + return target; + } + + def void implementsType(CtClass it, CtClass supertype) { + checkArgument(supertype.interface, "Supertype must be interface"); + addInterface(supertype); + } + + def asCtClass(Class class1) { + classPool.get(class1); + } + + def CtField field(CtClass it, String name, Class returnValue) { + val field = new CtField(returnValue.asCtClass, name, it); + field.modifiers = Modifier.PUBLIC + addField(field); + return field; + } + + def get(ClassPool pool, Class cls) { + try { + return pool.get(cls.name) + } catch (NotFoundException e) { + pool.appendClassPath(new LoaderClassPath(cls.classLoader)); + try { + return pool.get(cls.name) + + } catch (NotFoundException ef) { + pool.appendClassPath(new ClassClassPath(cls)); + return pool.get(cls.name) + } + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/MethodGenerator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/MethodGenerator.java new file mode 100644 index 0000000000..0eddbd6ace --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/MethodGenerator.java @@ -0,0 +1,7 @@ +package org.opendaylight.controller.sal.binding.codegen.util; + +import javassist.CtMethod; + +public interface MethodGenerator { + void process(CtMethod method); +} \ No newline at end of file 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 new file mode 100644 index 0000000000..2d67f11eb2 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend @@ -0,0 +1,776 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl + +import javassist.ClassPool +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType +import org.opendaylight.yangtools.yang.model.api.SchemaNode +import org.opendaylight.controller.sal.binding.codegen.util.JavassistUtils +import javassist.CtClass +import java.util.Map +import org.opendaylight.yangtools.yang.common.QName +import javassist.CtField +import static javassist.Modifier.* +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode +import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer +import org.opendaylight.yangtools.sal.binding.model.api.Type +import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder +import org.opendaylight.yangtools.binding.generator.util.Types +import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType +import java.util.HashMap +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode +import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode +import java.util.WeakHashMap +import java.util.List +import java.util.TreeSet +import com.google.common.base.Joiner +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject +import org.opendaylight.yangtools.sal.binding.model.api.Enumeration +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode +import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*; +import org.opendaylight.yangtools.yang.binding.BindingDeserializer +import org.opendaylight.yangtools.yang.binding.BindingSerializer +import org.opendaylight.yangtools.yang.binding.BindingCodec +import org.slf4j.LoggerFactory + +class TransformerGenerator { + + private static val log = LoggerFactory.getLogger(TransformerGenerator) + + public static val STRING = Types.typeForClass(String); + public static val BOOLEAN = Types.typeForClass(Boolean); + public static val INTEGER = Types.typeForClass(Integer); + + //public static val DECIMAL = Types.typeForClass(Decimal); + public static val LONG = Types.typeForClass(Long); + + val ClassPool classPool + val extension JavassistUtils utils; + + CtClass ctTransformator + + CtClass ctQName + + @Property + var Map typeDefinitions; + + @Property + var Map typeToDefinition + + @Property + var Map typeToSchemaNode + + val Map, Class> generatedClasses = new WeakHashMap(); + + public new(ClassPool pool) { + classPool = pool; + utils = new JavassistUtils(pool) + + ctTransformator = BindingCodec.asCtClass; + ctQName = QName.asCtClass + } + + def Class, Object>> transformerFor(Class inputType) { + return withClassLoader(inputType.classLoader) [ | + val ret = generatedClasses.get(inputType); + if (ret !== null) { + return ret as Class, Object>>; + } + val ref = Types.typeForClass(inputType) + val node = typeToSchemaNode.get(ref) + val typeSpecBuilder = typeToDefinition.get(ref) + val typeSpec = typeSpecBuilder.toInstance(); + val newret = generateTransformerFor(inputType, typeSpec, node) + generatedClasses.put(inputType, newret); + return newret as Class, Object>>; + ] + } + + def Class keyTransformerFor(Class inputType, GeneratedType type, ListSchemaNode schema) { + return withClassLoader(inputType.classLoader) [ | + val transformer = generatedClasses.get(inputType); + if (transformer != null) { + return transformer; + } + val newret = generateKeyTransformerFor(inputType, type, schema); + generatedClasses.put(inputType, newret); + return newret as Class, Object>>; + ] + } + + def Class keyTransformer(GeneratedType type, ListSchemaNode node) { + val cls = loadClassWithTCCL(type.resolvedName + "Key"); + keyTransformerFor(cls, type, node); + } + + private def serializer(Type type) { + val cls = loadClassWithTCCL(type.resolvedName); + transformerFor(cls); + + } + + def Class getValueSerializer(GeneratedTransferObject type) { + val cls = loadClassWithTCCL(type.resolvedName); + val transformer = generatedClasses.get(cls); + if (transformer !== null) { + return transformer; + } + val valueTransformer = generateValueTransformer(cls, type); + generatedClasses.put(cls, valueTransformer); + return valueTransformer; + } + + private def generateKeyTransformerFor(Class inputType, GeneratedType typeSpec, ListSchemaNode node) { + try { + log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader) + val properties = typeSpec.allProperties; + val ctCls = createClass(inputType.transformatorFqn) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + staticQNameField(node.QName); + implementsType(ctTransformator) + method(Object, "toDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = ''' + { + + return null; + } + ''' + ] + method(Object, "fromDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = ''' + { + if($2 == null){ + return null; + } + «QName.name» _localQName = $1; + java.util.Map _compositeNode = (java.util.Map) $2; + «FOR key : node.keyDefinition» + «val propertyName = key.getterName» + «val keyDef = node.getDataChildByName(key)» + «val property = properties.get(propertyName)» + «deserializeProperty(keyDef, property.returnType, property)»; + «ENDFOR» + «inputType.name» _value = new «inputType.name»(«node.keyDefinition.keyConstructorList»); + return _value; + } + ''' + ] + method(Object, "serialize", Object) [ + body = ''' + return toDomStatic(QNAME,$1); + ''' + ] + method(Object, "deserialize", Object) [ + body = ''' + return fromDomStatic(QNAME,$1); + ''' + ] + ] + val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain) + log.info("DOM Codec for {} was generated {}",inputType,ret) + return ret as Class, ?>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e); + val exception = new IllegalStateException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + } + + private def Class, D>> generateTransformerFor(Class inputType, + GeneratedType typeSpec, SchemaNode node) { + try { + log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader) + val ctCls = createClass(typeSpec.transformatorFqn) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + staticQNameField(inputType); + implementsType(ctTransformator) + method(Object, "toDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = serializeBodyFacade(typeSpec, node) + ] + method(Object, "serialize", Object) [ + body = ''' + return toDomStatic(QNAME,$1); + ''' + ] + method(Object, "fromDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = deserializeBody(typeSpec, node) + ] + method(Object, "deserialize", Object) [ + body = ''' + return fromDomStatic(QNAME,$1); + ''' + ] + ] + + val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain) + return ret as Class, D>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e); + val exception = new IllegalStateException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + } + + private def keyConstructorList(List qnames) { + val names = new TreeSet() + for (name : qnames) { + val fieldName = name.getterName; + names.add(fieldName); + } + return Joiner.on(",").join(names); + } + + private def serializeBodyFacade(GeneratedType type, SchemaNode node) { + val ret = serializeBody(type, node); + return ret; + } + + private def String deserializeBody(GeneratedType type, SchemaNode node) { + val ret = deserializeBodyImpl(type, node); + return ret; + } + + private def deserializeKey(GeneratedType type, ListSchemaNode node) { + if (node.keyDefinition != null && !node.keyDefinition.empty) { + return ''' + «type.resolvedName»Key getKey = («type.resolvedName»Key) «keyTransformer(type, node).canonicalName».fromDomStatic(_localQName,_compositeNode); + _builder.setKey(getKey); + '''; + } + } + + private def dispatch String deserializeBodyImpl(GeneratedType type, SchemaNode node) ''' + { + «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName()); + + if($2 == null) { + return null; + } + java.util.Map _compositeNode = (java.util.Map) $2; + «type.builderName» _builder = new «type.builderName»(); + + return _builder.build(); + } + ''' + + private def dispatch String deserializeBodyImpl(GeneratedType type, ListSchemaNode node) ''' + { + «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName()); + if($2 == null) { + return null; + } + java.util.Map _compositeNode = (java.util.Map) $2; + «type.builderName» _builder = new «type.builderName»(); + «deserializeKey(type, node)» + «deserializeDataNodeContainerBody(type, node)» + return _builder.build(); + } + ''' + + private def dispatch String deserializeBodyImpl(GeneratedType type, ContainerSchemaNode node) ''' + { + «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName()); + if($2 == null) { + return null; + } + java.util.Map _compositeNode = (java.util.Map) $2; + «type.builderName» _builder = new «type.builderName»(); + «deserializeDataNodeContainerBody(type, node)» + return _builder.build(); + } + ''' + + private def dispatch String deserializeBodyImpl(GeneratedType type, ChoiceCaseNode node) ''' + { + «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName()); + if($2 == null) { + return null; + } + java.util.Map _compositeNode = (java.util.Map) $2; + «type.builderName» _builder = new «type.builderName»(); + «deserializeDataNodeContainerBody(type, node)» + return _builder.build(); + } + ''' + + private def deserializeDataNodeContainerBody(GeneratedType type, DataNodeContainer node) { + deserializeNodeContainerBodyImpl(type, type.allProperties, node); + } + + private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap properties, + DataNodeContainer node) { + val ret = ''' + «FOR child : node.childNodes.filter[!augmenting]» + «val signature = properties.get(child.getterName)» + «deserializeProperty(child, signature.returnType, signature)» + _builder.«signature.name.toSetter»(«signature.name»); + «ENDFOR» + ''' + return ret; + } + + private def dispatch CharSequence deserializeProperty(ListSchemaNode schema, ParameterizedType type, + MethodSignature property) ''' + java.util.List _dom_«property.name» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName. + localName»")); + //System.out.println("«property.name»#deCode"+_dom_«property.name»); + java.util.List «property.name» = new java.util.ArrayList(); + if(_dom_«property.name» != null) { + java.util.List _serialized = new java.util.ArrayList(); + java.util.Iterator _iterator = _dom_«property.name».iterator(); + boolean _hasNext = _iterator.hasNext(); + while(_hasNext) { + Object _listItem = _iterator.next(); + //System.out.println(" item" + _listItem); + Object _value = «type.actualTypeArguments.get(0).serializer.name».fromDomStatic(_localQName,_listItem); + //System.out.println(" value" + _value); + «property.name».add(_value); + _hasNext = _iterator.hasNext(); + } + } + + //System.out.println(" list" + «property.name»); + ''' + + private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type, + MethodSignature property) ''' + java.util.List _dom_«property.name» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName. + localName»")); + java.util.List «property.name» = new java.util.ArrayList(); + if(_dom_«property.name» != null) { + java.util.List _serialized = new java.util.ArrayList(); + java.util.Iterator _iterator = _dom_«property.name».iterator(); + boolean _hasNext = _iterator.hasNext(); + while(_hasNext) { + 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")»; + «property.name».add(_value); + } + _hasNext = _iterator.hasNext(); + } + } + ''' + + private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, MethodSignature property) ''' + java.util.List _dom_«property.name»_list = + _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»")); + «type.resolvedName» «property.name» = null; + if(_dom_«property.name»_list != null && _dom_«property.name»_list.size() > 0) { + java.util.Map.Entry _dom_«property.name» = (java.util.Map.Entry) _dom_«property.name»_list.get(0); + Object _inner_value = _dom_«property.name».getValue(); + «property.name» = «deserializeValue(type, "_inner_value")»; + } + ''' + + private def dispatch CharSequence deserializeProperty(ContainerSchemaNode schema, Type type, + MethodSignature property) ''' + java.util.List _dom_«property.name»_list = + _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»")); + «type.resolvedName» «property.name» = null; + if(_dom_«property.name»_list != null && _dom_«property.name»_list.size() > 0) { + + java.util.Map _dom_«property.name» = (java.util.Map) _dom_«property.name»_list.get(0); + «type.resolvedName» «property.name» = «type.serializer.name».fromDomStatic(_localQName,_dom_«property.name»); + } + ''' + + private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter) ''' + («type.resolvedName») «type.valueSerializer.name».fromDomValue(«domParameter»); + ''' + + private def dispatch Class, Object>> generateValueTransformer( + Class inputType, GeneratedTransferObject typeSpec) { + try { + + val returnType = typeSpec.valueReturnType; + if (returnType == null) { + + val ctCls = createDummyImplementation(inputType, typeSpec); + val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain) + return ret as Class, Object>>; + } + val ctCls = createClass(typeSpec.transformatorFqn) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + implementsType(ctTransformator) + implementsType(BindingDeserializer.asCtClass) + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = ''' + { + ////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); + «returnType.resolvedName» _value = _encapsulatedValue.getValue(); + //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value); + return _value; + } + ''' + ] + method(Object, "serialize", Object) [ + body = ''' + { + return toDomValue($1); + } + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = ''' + { + //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + + if($1 == null) { + return null; + } + «returnType.name» _simpleValue = «deserializeValue(returnType, "$1")»; + «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(_simpleValue); + return _value; + } + ''' + ] + method(Object, "deserialize", Object) [ + body = '''{ + return fromDomValue($1); + } + ''' + ] + ] + + val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain) + log.info("DOM Codec for {} was generated {}",inputType,ret) + return ret as Class, Object>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e); + val exception = new IllegalStateException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + + } + + private def createDummyImplementation(Class object, GeneratedTransferObject typeSpec) { + log.info("Generating Dummy DOM Codec for {} with {}",object,object.classLoader) + return createClass(typeSpec.transformatorFqn) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + implementsType(ctTransformator) + implementsType(BindingDeserializer.asCtClass) + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = '''return null;''' + ] + method(Object, "serialize", Object) [ + body = ''' + { + return toDomValue($1); + } + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = '''return null;''' + ] + method(Object, "deserialize", Object) [ + body = '''{ + return fromDomValue($1); + } + ''' + ] + ] + } + + def Type getValueReturnType(GeneratedTransferObject object) { + for (prop : object.properties) { + if (prop.name == "value") { + return prop.returnType; + } + } + if (object.superType != null) { + return getValueReturnType(object.superType); + } + return null; + } + + private def dispatch Class, Object>> generateValueTransformer( + Class inputType, Enumeration typeSpec) { + try { + log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader) + val ctCls = createClass(typeSpec.transformatorFqn) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + implementsType(ctTransformator) + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = ''' + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1; + return _value.getValue(); + ''' + ] + method(Object, "serialize", Object) [ + body = ''' + return toDomValue($1); + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = ''' + if($1 == null) { + return null; + } + _simpleValue = null; + «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(null); + return _value; + ''' + ] + method(Object, "deserialize", Object) [ + body = ''' + return fromDomValue($1); + ''' + ] + ] + + val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain) + log.info("DOM Codec for {} was generated {}",inputType,ret) + return ret as Class, Object>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e); + val exception = new IllegalStateException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + + } + + private def dispatch String deserializeValue(Type type, String domParameter) '''(«type.resolvedName») «domParameter»''' + + /** + * Default catch all + * + **/ + private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, MethodSignature property) ''' + «type.resolvedName» «property.name» = null; + ''' + + private def dispatch CharSequence deserializeProperty(DataSchemaNode container, GeneratedTypeBuilder type, + MethodSignature property) { + _deserializeProperty(container, type.toInstance, property) + } + + public static def toSetter(String it) { + + if (startsWith("is")) { + return "set" + substring(2); + } else if (startsWith("get")) { + return "set" + substring(3); + } + return "set" + it; + } + + /* + private def dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, MethodSignature property) ''' + «property.returnType.resolvedName» «property.name» = value.«property.name»(); + if(«property.name» != null) { + Object domValue = «type.serializer».toDomStatic(QNAME,«property.name»); + childNodes.add(domValue); + } + ''' + */ + private def getBuilderName(GeneratedType type) '''«type.resolvedName»Builder''' + + private def staticQNameField(CtClass it, Class node) { + val field = new CtField(ctQName, "QNAME", it); + field.modifiers = PUBLIC + FINAL + STATIC; + addField(field, '''«node.name».QNAME''') + } + + private def staticQNameField(CtClass it, QName node) { + val field = new CtField(ctQName, "QNAME", it); + field.modifiers = PUBLIC + FINAL + STATIC; + addField(field, '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''') + } + + private def dispatch String serializeBody(GeneratedType type, ListSchemaNode node) ''' + { + «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName()); + java.util.List childNodes = new java.util.ArrayList(); + «type.resolvedName» value = («type.resolvedName») $2; + «transformDataContainerBody(type.allProperties, node)» + return ($r) java.util.Collections.singletonMap(resultName,childNodes); + } + ''' + + private def dispatch String serializeBody(GeneratedType type, ContainerSchemaNode node) ''' + { + «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName()); + java.util.List childNodes = new java.util.ArrayList(); + «type.resolvedName» value = («type.resolvedName») $2; + «transformDataContainerBody(type.allProperties, node)» + return ($r) java.util.Collections.singletonMap(resultName,childNodes); + } + ''' + + private def transformDataContainerBody(Map properties, DataNodeContainer node) { + val ret = ''' + «FOR child : node.childNodes.filter[!augmenting]» + «val signature = properties.get(child.getterName)» + «serializeProperty(child, signature.returnType, signature)» + «ENDFOR» + ''' + return ret; + } + + private static def String getGetterName(DataSchemaNode node) { + return "get" + BindingGeneratorUtil.parseToClassName(node.QName.localName); + } + + private static def String getGetterName(QName node) { + return "get" + BindingGeneratorUtil.parseToClassName(node.localName); + } + + private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type, + MethodSignature property) ''' + «property.returnType.resolvedName» «property.name» = value.«property.name»(); + if(«property.name» != null) { + java.util.Iterator _iterator = «property.name».iterator(); + boolean _hasNext = _iterator.hasNext(); + while(_hasNext) { + Object _listItem = _iterator.next(); + Object _domValue = «type.actualTypeArguments.get(0).serializer.name».toDomStatic(QNAME,_listItem); + childNodes.add(_domValue); + _hasNext = _iterator.hasNext(); + } + } + ''' + + private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, MethodSignature property) ''' + «property.returnType.resolvedName» «property.name» = value.«property.name»(); + + if(«property.name» != null) { + «QName.name» _qname = «QName.name».create(resultName,"«schema.QName.localName»"); + Object _propValue = «serializeValue(type, property.name)»; + if(_propValue != null) { + Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); + childNodes.add(_domValue); + } + } + ''' + + private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.name».toDomValue(«parameter»)''' + + private def dispatch serializeValue(Type signature, String property) '''«property»''' + + private def dispatch CharSequence serializeProperty(LeafListSchemaNode schema, Type type, MethodSignature property) ''' + «property.returnType.resolvedName» «property.name» = value.«property.name»(); + if(«property.name» != null) { + «QName.name» _qname = «QName.name».create(resultName,"«schema.QName.localName»"); + java.util.Iterator _iterator = «property.name».iterator(); + boolean _hasNext = _iterator.hasNext(); + while(_hasNext) { + Object _listItem = _iterator.next(); + Object _propValue = «property.name»; + Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); + childNodes.add(_domValue); + _hasNext = _iterator.hasNext(); + } + } + ''' + + /** + * Default catch all + * + **/ + private def dispatch CharSequence serializeProperty(DataSchemaNode container, Type type, MethodSignature property) ''' + «property.returnType.resolvedName» «property.name» = value.«property.name»(); + if(«property.name» != null) { + Object domValue = «property.name»; + childNodes.add(domValue); + } + ''' + + private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedTypeBuilder type, + MethodSignature property) { + serializeProperty(container, type.toInstance, property) + } + + private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedType type, + MethodSignature property) ''' + «property.returnType.resolvedName» «property.name» = value.«property.name»(); + if(«property.name» != null) { + Object domValue = «type.serializer».toDomStatic(QNAME,«property.name»); + childNodes.add(domValue); + } + ''' + + private def dispatch String serializeBody(GeneratedType type, SchemaNode node) ''' + { + return ($r) java.util.Collections.singletonMap(this.QNAME,null); + } + ''' + + private def transformatorFqn(GeneratedType typeSpec) { + return '''«typeSpec.resolvedName»$Broker$Codec$DOM''' + } + + private def transformatorFqn(Class typeSpec) { + return '''«typeSpec.name»$Broker$Codec$DOM''' + } + + private def HashMap getAllProperties(GeneratedType type) { + val ret = new HashMap(); + type.collectAllProperties(ret); + return ret; + } + + private def dispatch void collectAllProperties(GeneratedType type, Map set) { + for (definition : type.methodDefinitions) { + set.put(definition.name, definition); + } + + for (parent : type.implements) { + parent.collectAllProperties(set); + } + } + + private def dispatch void collectAllProperties(Type type, Map set) { + // NOOP for generic type. + } + + def String getResolvedName(Type type) { + return type.asCtClass.name; + } + + def CtClass asCtClass(Type type) { + val name = type.fullyQualifiedName + val cls = loadClassWithTCCL(type.fullyQualifiedName) + return cls.asCtClass; + } + +} + +@Data +class PropertyPair { + + String getterName; + + Type type; + + @Property + MethodSignature signature; + @Property + SchemaNode schemaNode; +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend index 0a8a7df41c..e2b79203c9 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend @@ -47,10 +47,20 @@ import org.opendaylight.yangtools.yang.data.api.SimpleNode import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition +import com.google.common.collect.HashMultimap +import com.google.common.collect.ArrayListMultimap +import com.google.common.collect.Multimap +import java.util.Collection +import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature class BindingMapping { + + + @Property val Map typeToDefinition = new HashMap(); + + @Property val Map typeToSchemaNode = new HashMap(); def QName getSchemaNode(Class cls) { @@ -91,7 +101,7 @@ class BindingMapping { } - def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument, Class parent) { + private def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument, Class parent) { val Class rawType = argument.type; val ref = Types.typeForClass(rawType); val schemaType = typeToSchemaNode.get(ref); @@ -103,13 +113,13 @@ class BindingMapping { return new NodeIdentifierWithPredicates(qname, predicates); } - def dispatch PathArgument toDataDomPathArgument(Item argument, Class parent) { + private def dispatch PathArgument toDataDomPathArgument(Item argument, Class parent) { val ref = Types.typeForClass(argument.type); val qname = typeToSchemaNode.get(ref).QName return new NodeIdentifier(qname); } - def Map toPredicates(Object identifier, ListSchemaNode node) { + private def Map toPredicates(Object identifier, ListSchemaNode node) { val keyDefinitions = node.keyDefinition; val map = new HashMap(); for (keydef : keyDefinitions) { @@ -192,7 +202,7 @@ class BindingMapping { return Collections.emptyList(); } - def getSimpleValues(DataContainer container, LeafListSchemaNode node) { + private def getSimpleValues(DataContainer container, LeafListSchemaNode node) { return Collections.emptyList(); } @@ -226,35 +236,35 @@ class BindingMapping { return it; } - private def dispatch Node getSimpleValue(Object container, QName name, ExtendedType type) { + public static def dispatch Node getSimpleValue(Object container, QName name, ExtendedType type) { getSimpleValue(container, name, type.baseType); } - private def dispatch Node getSimpleValue(Object container, QName name, StringTypeDefinition type) { + public static def dispatch Node getSimpleValue(Object container, QName name, StringTypeDefinition type) { val value = container.getValue(name, String); if(value === null) return null; return new SimpleNodeTOImpl(name, null, value); } - private def dispatch Node getSimpleValue(Object container, QName name, TypeDefinition type) { + public static def dispatch Node getSimpleValue(Object container, QName name, TypeDefinition type) { val value = container.getValue(name, Object); if(value === null) return null; return new SimpleNodeTOImpl(name, null, value); } - private def dispatch Node getSimpleValue(Object container, QName name, BooleanTypeDefinition type) { + public static def dispatch Node getSimpleValue(Object container, QName name, BooleanTypeDefinition type) { val value = container.getValue(name, Boolean); if(value === null) return null; return new SimpleNodeTOImpl(name, null, value); } - private def dispatch Node getSimpleValue(Object container, QName name, BinaryTypeDefinition type) { + public static def dispatch Node getSimpleValue(Object container, QName name, BinaryTypeDefinition type) { val Object value = container.getValue(name, Object); //Constants.BYTES_CLASS); if(value === null) return null; return new SimpleNodeTOImpl(name, null, value); } - private def T getValue(Object object, QName node, Class type) { + public static def T getValue(Object object, QName node, Class type) { val methodName = BindingGeneratorImpl.getterMethodName(node.localName, Types.typeForClass(type)); var clz = object.class; if (object instanceof DataContainer) { @@ -274,7 +284,7 @@ class BindingMapping { return value.getEncapsulatedValue(type); } - private def T getEncapsulatedValue(Object value, Class type) { + public static def T getEncapsulatedValue(Object value, Class type) { val method = value.class.getMethod("getValue"); if (method !== null && type.isAssignableFrom(method.returnType)) { return method.invoke(value) as T; @@ -303,7 +313,7 @@ class BindingMapping { return buildMethod.invoke(builder) as DataObject; } - def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, + private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, ListSchemaNode schema) { if (schema.keyDefinition !== null && !schema.keyDefinition.empty) { @@ -311,14 +321,56 @@ class BindingMapping { val value = node.keyToBindingKey(loader, type, schema); builder.setProperty("key", value); } + node.fillBuilderFromContainer(builder,loader,type,schema); } + + - def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, + private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, ContainerSchemaNode schema) { + node.fillBuilderFromContainer(builder,loader,type,schema); } - def Object keyToBindingKey(CompositeNode node, ClassLoader loader, GeneratedType type, ListSchemaNode schema) { + private def void fillBuilderFromContainer(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, DataNodeContainer schema) { + val Multimap> dataMap = ArrayListMultimap.create(); + for(child :node.children) { + dataMap.put(child.nodeType,node); + } + for(entry : dataMap.asMap.entrySet) { + val entrySchema = schema.getDataChildByName(entry.key); + val entryType = type.methodDefinitions.byQName(entry.key); + entry.value.addValueToBuilder(builder,loader,entryType,entrySchema); + } + } + + private def Type byQName(List signatures, QName name) { + + } + + private def dispatch addValueToBuilder(Collection> nodes, Object object, ClassLoader loader, Object object2, LeafSchemaNode container) { + + } + + + + private def dispatch addValueToBuilder(Collection> nodes, Object object, ClassLoader loader, Object object2, ContainerSchemaNode container) { + + } + + + private def dispatch addValueToBuilder(Collection> nodes, Object object, ClassLoader loader, Object object2, ListSchemaNode container) { + + } + + private def dispatch addValueToBuilder(Collection> nodes, Object object, ClassLoader loader, Object object2, LeafListSchemaNode container) { + + } + + + + + private def Object keyToBindingKey(CompositeNode node, ClassLoader loader, GeneratedType type, ListSchemaNode schema) { val keyClass = loader.loadClass(type.keyFQN); val constructor = keyClass.constructors.get(0); val keyType = type.keyTypeProperties; @@ -336,22 +388,22 @@ class BindingMapping { return ClassLoaderUtils.construct(constructor, args); } - def dispatch Object deserializeSimpleValue(SimpleNode node, ClassLoader loader, Type type, + private def dispatch Object deserializeSimpleValue(SimpleNode node, ClassLoader loader, Type type, LeafSchemaNode node2) { deserializeSimpleValueImpl(node, loader, type, node2.type); } - def dispatch Object deserializeSimpleValue(SimpleNode node, ClassLoader loader, Type type, + private def dispatch Object deserializeSimpleValue(SimpleNode node, ClassLoader loader, Type type, LeafListSchemaNode node2) { deserializeSimpleValueImpl(node, loader, type, node2.type); } - def dispatch Object deserializeSimpleValueImpl(SimpleNode node, ClassLoader loader, Type type, + private def dispatch Object deserializeSimpleValueImpl(SimpleNode node, ClassLoader loader, Type type, ExtendedType definition) { deserializeSimpleValueImpl(node, loader, type, definition.baseType); } - def dispatch Object deserializeSimpleValueImpl(SimpleNode node, ClassLoader loader, Type type, + private def dispatch Object deserializeSimpleValueImpl(SimpleNode node, ClassLoader loader, Type type, StringTypeDefinition definition) { if (type instanceof GeneratedTransferObject) { val cls = loader.getClassForType(type); @@ -362,16 +414,16 @@ class BindingMapping { return node.value; } - def Class getClassForType(ClassLoader loader, Type type) { + private def Class getClassForType(ClassLoader loader, Type type) { loader.loadClass(type.fullyQualifiedName); } - def dispatch Object deserializeSimpleValueImpl(SimpleNode node, ClassLoader loader, Type type, + private def dispatch Object deserializeSimpleValueImpl(SimpleNode node, ClassLoader loader, Type type, TypeDefinition definition) { throw new UnsupportedOperationException("TODO: auto-generated method stub") } - def Map getKeyTypeProperties(GeneratedType type) { + private def Map getKeyTypeProperties(GeneratedType type) { val method = FluentIterable.from(type.methodDefinitions).findFirst[name == "getKey"] val key = method.returnType as GeneratedTransferObject; val ret = new HashMap(); @@ -381,16 +433,16 @@ class BindingMapping { return ret; } - def void setProperty(Object object, String property, Object value) { + private def void setProperty(Object object, String property, Object value) { val cls = object.class; val valMethod = cls.getMethod("set" + property.toFirstUpper, value.class); if (valMethod != null) valMethod.invoke(object, value); } - def String getBuilderFQN(Type type) '''«type.fullyQualifiedName»Builder''' + private def String getBuilderFQN(Type type) '''«type.fullyQualifiedName»Builder''' - def String getKeyFQN(Type type) '''«type.fullyQualifiedName»Key''' + private def String getKeyFQN(Type type) '''«type.fullyQualifiedName»Key''' } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/CompositeNodeUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/CompositeNodeUtils.java new file mode 100644 index 0000000000..5d17d92cd4 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/CompositeNodeUtils.java @@ -0,0 +1,5 @@ +package org.opendaylight.controller.sal.binding.impl.connect.dom; + +public class CompositeNodeUtils { + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/ConnectorActivator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/ConnectorActivator.java index c96835bd94..af18e9c0cb 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/ConnectorActivator.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/ConnectorActivator.java @@ -3,7 +3,10 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom; import java.util.Collection; import java.util.Collections; +import javassist.ClassPool; + import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; @@ -38,10 +41,12 @@ public class ConnectorActivator implements Provider, ServiceTrackerCustomizer
typeDefinitions = new ConcurrentHashMap(); + + val ConcurrentMap, TransformerWrapper> domSerializers = new ConcurrentHashMap(); + + @Property + val ConcurrentMap typeToDefinition = new ConcurrentHashMap(); + + @Property + val ConcurrentMap typeToSchemaNode = new ConcurrentHashMap(); + + override onGlobalContextUpdated(SchemaContext arg0) { + recreateBindingContext(arg0); + } + + def recreateBindingContext(SchemaContext schemaContext) { + val newBinding = new BindingGeneratorImpl(); + newBinding.generateTypes(schemaContext); + + for (entry : newBinding.moduleContexts.entrySet) { + + //val module = entry.key; + val context = entry.value; + updateBindingFor(context.childNodes, schemaContext); + + val typedefs = context.typedefs; + for(typedef : typedefs.values) { + binding.typeDefinitions.put(typedef,typedef as GeneratedType); + } + } + } + + override CompositeNode toDataDom(DataObject data) { + toCompositeNodeImpl(data); + } + + override Entry toDataDom( + Entry, DataObject> entry) { + val key = toDataDomImpl(entry.key); + val data = toCompositeNodeImpl(entry.value); + return new SimpleEntry(key, data); + } + + private def CompositeNode toCompositeNodeImpl(DataObject object) { + val cls = object.implementedInterface; + val transformator = resolveTransformator(cls); + val ret = transformator.transform(object); + return ret; + } + + private def resolveTransformator(Class cls) { + val serializer = domSerializers.get(cls); + if (serializer !== null) { + return serializer; + } + val transformerClass = binding.transformerFor(cls).newInstance; + val wrapper = new TransformerWrapper(transformerClass); + domSerializers.putIfAbsent(cls, wrapper); + return wrapper; + } + + private def org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDomImpl( + InstanceIdentifier object) { + val pathArguments = object.path; + var Class parent; + val dataDomArgs = new ArrayList(); + for (pathArgument : pathArguments) { + dataDomArgs.add(pathArgument.toDataDomPathArgument(parent)); + parent = pathArgument.type; + } + + return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(dataDomArgs); + } + + override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom( + InstanceIdentifier path) { + return toDataDomImpl(path); + } + + override dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result) { + return dataObjectFromDataDomImpl(path, result); + } + + def DataObject dataObjectFromDataDomImpl(InstanceIdentifier identifier, CompositeNode node) { + val targetType = identifier.targetType + val transformer = resolveTransformator(targetType); + val ret = transformer.deserialize(node) as DataObject; + return ret; + } + + def void updateBindingFor(Map map, SchemaContext module) { + for (entry : map.entrySet) { + val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key); + typeToDefinition.put(entry.value, entry.value); + typeToSchemaNode.put(entry.value, schemaNode) + } + } + + private def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument, + Class parent) { + val Class rawType = argument.type; + val ref = Types.typeForClass(rawType); + val schemaType = typeToSchemaNode.get(ref); + val qname = schemaType.QName + + val Object key = argument.key; + val predicates = key.toPredicates(schemaType as ListSchemaNode); + + return new NodeIdentifierWithPredicates(qname, predicates); + } + + private def Map toPredicates(Object identifier, ListSchemaNode node) { + val keyDefinitions = node.keyDefinition; + val map = new HashMap(); + for (keydef : keyDefinitions) { + val keyNode = node.getDataChildByName(keydef) as LeafSchemaNode; + val value = BindingMapping.getSimpleValue(identifier, keydef, keyNode.type); + map.put(keydef, value.value); + } + return map; + } + + private def dispatch PathArgument toDataDomPathArgument(Item argument, Class parent) { + val ref = Types.typeForClass(argument.type); + val qname = typeToSchemaNode.get(ref).QName + return new NodeIdentifier(qname); + } + + public def void start() { + pool = new ClassPool() + binding = new TransformerGenerator(pool); + + binding.typeToDefinition = typeToDefinition + binding.typeToSchemaNode = typeToSchemaNode + binding.typeDefinitions = typeDefinitions + + } +} + +class TransformerWrapper implements // // +Delegator, Object>> { + + @Property + val BindingCodec, Object> delegate; + + new(BindingCodec, Object> delegate) { + _delegate = delegate; + } + + def CompositeNode transform(DataObject input) { + val ret = delegate.serialize(input); + val node = toNode(ret) + return node as CompositeNode; + } + + def deserialize(CompositeNode node) { + if (node === null) { + return null; + } + val Map mapCapture = node + return delegate.deserialize(mapCapture as Map); + } + + static def Node toNode(Map map) { + val nodeMap = map as Map; + checkArgument(map.size == 1); + val elem = nodeMap.entrySet.iterator.next; + val qname = elem.key; + val value = elem.value; + toNodeImpl(qname, value); + } + + static def dispatch Node toNodeImpl(QName name, List objects) { + val values = new ArrayList>(objects.size); + for (obj : objects) { + values.add(toNode(obj as Map)); + } + return new CompositeNodeTOImpl(name, null, values); + } + + static def dispatch Node toNodeImpl(QName name, Map object) { + throw new UnsupportedOperationException("Unsupported node hierarchy."); + } + + static def dispatch Node toNodeImpl(QName name, Object object) { + return new SimpleNodeTOImpl(name, null, object); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java index ccf99dfe37..0b91658a18 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java @@ -10,8 +10,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; -import org.opendaylight.yangtools.yang.binding.Identifier; - public class ClassLoaderUtils { public static V withClassLoader(ClassLoader cls,Callable function) throws Exception { @@ -33,4 +31,9 @@ public class ClassLoaderUtils { Object[] initargs = objects.toArray(new Object[]{}); return constructor.newInstance(initargs); } + + + public static Class loadClassWithTCCL(String name) throws ClassNotFoundException { + return Thread.currentThread().getContextClassLoader().loadClass(name); + } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java index 0448238665..0e35ee650e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java @@ -14,7 +14,9 @@ import org.opendaylight.controller.sal.binding.api.data.DataModificationTransact import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.impl.connect.dom.MappingServiceImpl; +import org.opendaylight.controller.sal.binding.impl.connect.dom.RuntimeGeneratedMappingServiceImpl; import org.opendaylight.controller.sal.core.api.data.DataBrokerService; import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; @@ -34,8 +36,8 @@ public class BrokerIntegrationTest { DataBrokerService biDataService; DataProviderService baDataService; - private MappingServiceImpl mappingServiceImpl; - private MappingServiceImpl mappingService; + private RuntimeGeneratedMappingServiceImpl mappingServiceImpl; + private BindingIndependentMappingService mappingService; private DataBrokerImpl baDataImpl; private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl; private ListeningExecutorService executor; @@ -60,9 +62,9 @@ public class BrokerIntegrationTest { biDataImpl.registerOperationalReader(treeRoot, dataStore); biDataImpl.registerCommitHandler(treeRoot, dataStore); - mappingServiceImpl = new MappingServiceImpl(); + mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl(); mappingService = mappingServiceImpl; - + mappingServiceImpl.start(); connectorServiceImpl = new BindingIndependentDataServiceConnector(); connectorServiceImpl.setBaDataService(baDataService); @@ -73,20 +75,21 @@ public class BrokerIntegrationTest { String[] yangFiles = new String[] { "yang-ext.yang", "ietf-inet-types.yang", "ietf-yang-types.yang", "node-inventory.yang" }; - mappingService.onGlobalContextUpdated(MappingServiceTest.getContext(yangFiles)); + mappingServiceImpl.onGlobalContextUpdated(MappingServiceTest.getContext(yangFiles)); + } @Test public void simpleModifyOperation() throws Exception { - DataModificationTransaction transaction = baDataService.beginTransaction(); - assertNotNull(transaction); NodeRef node1 = createNodeRef("0"); DataObject node = baDataService.readConfigurationData(node1.getValue()); assertNull(node); Node nodeData1 = createNode("0"); + + DataModificationTransaction transaction = baDataService.beginTransaction(); transaction.putConfigurationData(node1.getValue(), nodeData1); Future> commitResult = transaction.commit(); assertNotNull(commitResult); @@ -102,18 +105,50 @@ public class BrokerIntegrationTest { assertEquals(nodeData1.getKey(), readedData.getKey()); - DataModificationTransaction transaction2 = baDataService.beginTransaction(); + NodeRef nodeFoo = createNodeRef("foo"); + NodeRef nodeBar = createNodeRef("bar"); + Node nodeFooData = createNode("foo"); + Node nodeBarData = createNode("bar"); + + + DataModificationTransaction insertMoreTr = baDataService.beginTransaction(); + insertMoreTr.putConfigurationData(nodeFoo.getValue(), nodeFooData); + insertMoreTr.putConfigurationData(nodeBar.getValue(), nodeBarData); + RpcResult result2 = insertMoreTr.commit().get(); + + assertNotNull(result2); + assertNotNull(result2.getResult()); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + + Nodes allNodes = (Nodes) baDataService.readConfigurationData(InstanceIdentifier.builder().node(Nodes.class).toInstance()); + assertNotNull(allNodes); + assertNotNull(allNodes.getNode()); + assertEquals(3, allNodes.getNode().size()); + + + /** + * We create transaction no 2 + * + */ + DataModificationTransaction removalTransaction = baDataService.beginTransaction(); assertNotNull(transaction); - transaction2.removeConfigurationData(node1.getValue()); + /** + * We remove node 1 + * + */ + removalTransaction.removeConfigurationData(node1.getValue()); - Future> commitResult2 = transaction2.commit(); + /** + * We commit transaction + */ + Future> commitResult2 = removalTransaction.commit(); assertNotNull(commitResult2); - RpcResult result2 = commitResult2.get(); + RpcResult result3 = commitResult2.get(); - assertNotNull(result2); - assertNotNull(result2.getResult()); + assertNotNull(result3); + assertNotNull(result3.getResult()); assertEquals(TransactionStatus.COMMITED, result2.getResult()); DataObject readedData2 = baDataService.readConfigurationData(node1.getValue()); -- 2.36.6