From: Tony Tkacik Date: Fri, 15 Nov 2013 14:43:43 +0000 (+0100) Subject: Fix for Bug 144, Bug 147, 148 - improved codec X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~376 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=9d90b3f545a3ac32b198a5cabe606b411a6d081b Fix for Bug 144, Bug 147, 148 - improved codec - Added defensive locking mechanism to class generation code - Provider's and Consumer's crossing boundatories between brokers are blocked util their YANG schema is ready and processed. - Added set of APIs to make generated codec contracts and interactions more explicit. - Extracted augmentation serialization / deserialization to sepparate generated codec (one codec per augmentation type). - Fixed NPE Change-Id: I299924e911f63aba1fdeca3debeb8cc80f66f5ac Signed-off-by: Tony Tkacik --- diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend index 5b11ec7207..b6dcde19ee 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend @@ -8,7 +8,6 @@ import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeC import java.util.Set import java.util.HashMap import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable -import static org.opendaylight.controller.sal.binding.codegen.impl.XtendHelper.* import org.opendaylight.yangtools.yang.binding.DataContainer import org.opendaylight.yangtools.yang.binding.RpcImplementation 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 21b48bb475..8309651446 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 @@ -9,8 +9,4 @@ public class XtendHelper { Class cls) { return new RpcRoutingTableImpl<>(cls); } - - public static String foo() { - return "Foo"; - } } 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 index 19737b83c6..802e7acb5b 100644 --- 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 @@ -10,10 +10,15 @@ import javassist.Modifier import javassist.NotFoundException import javassist.LoaderClassPath import javassist.ClassClassPath +import java.util.concurrent.locks.Lock +import java.util.concurrent.locks.ReentrantLock class JavassistUtils { ClassPool classPool + + @Property + val Lock lock = new ReentrantLock(); new(ClassPool pool) { classPool = pool; @@ -49,12 +54,14 @@ class JavassistUtils { } 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); @@ -76,6 +83,13 @@ class JavassistUtils { addField(field); return field; } + + def CtField staticField(CtClass it, String name, Class returnValue) { + val field = new CtField(returnValue.asCtClass, name, it); + field.modifiers = Modifier.PUBLIC + Modifier.STATIC + addField(field); + return field; + } def get(ClassPool pool, Class cls) { try { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/AugmentationCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/AugmentationCodec.java new file mode 100644 index 0000000000..cdddec76d4 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/AugmentationCodec.java @@ -0,0 +1,15 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; + +public interface AugmentationCodec> extends DomCodec { + + + @Override + public CompositeNode serialize(ValueWithQName input); + + @Override + public ValueWithQName deserialize(Node input); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCaseCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCaseCodec.java new file mode 100644 index 0000000000..d545b72844 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCaseCodec.java @@ -0,0 +1,16 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; + +public interface ChoiceCaseCodec extends DataContainerCodec { + + @Override + public CompositeNode serialize(ValueWithQName input); + + @Override + public ValueWithQName deserialize(Node input); + + public boolean isAcceptable(Node input); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCodec.java new file mode 100644 index 0000000000..21bb1cf79a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCodec.java @@ -0,0 +1,12 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import org.opendaylight.yangtools.yang.data.api.Node; + +public interface ChoiceCodec extends DomCodec { + + @Override + public Node serialize(ValueWithQName input); + + @Override + public ValueWithQName deserialize(Node input); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java new file mode 100644 index 0000000000..1a02ea17e4 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java @@ -0,0 +1,32 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.Identifier; + +import java.util.List; + +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec; + + +public interface CodecRegistry { + + InstanceIdentifierCodec getInstanceIdentifierCodec(); + + DataContainerCodec getCodecForDataObject(Class object); + + > IdentifierCodec getIdentifierCodecForIdentifiable(Class object); + + > IdentifierCodec getCodecForIdentifier(Class object); + + > AugmentationCodec getCodecForAugmentation(Class object); + + Class getClassForPath(List names); + + IdentifierCodec getKeyCodecForPath(List names); + + + void bindingClassEncountered(Class cls); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DataContainerCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DataContainerCodec.java new file mode 100644 index 0000000000..683faaf73b --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DataContainerCodec.java @@ -0,0 +1,17 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; + +public interface DataContainerCodec extends DomCodec { + + + @Override + public ValueWithQName deserialize(Node input); + + @Override + public CompositeNode serialize(ValueWithQName input); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DomCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DomCodec.java new file mode 100644 index 0000000000..76969ab44a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DomCodec.java @@ -0,0 +1,17 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.Node; + +public interface DomCodec extends BindingCodec, ValueWithQName>{ + + + @Override + public Node serialize(ValueWithQName input); + + + @Override + public ValueWithQName deserialize(Node input); + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentifierCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentifierCodec.java new file mode 100644 index 0000000000..933b884483 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentifierCodec.java @@ -0,0 +1,14 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; + +public interface IdentifierCodec> extends DomCodec { + + @Override + public ValueWithQName deserialize(Node input); + + @Override + public CompositeNode serialize(ValueWithQName input); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/InstanceIdentifierCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/InstanceIdentifierCodec.java new file mode 100644 index 0000000000..7fbb79d74f --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/InstanceIdentifierCodec.java @@ -0,0 +1,13 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public interface InstanceIdentifierCodec extends BindingCodec> { + + @Override + public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier serialize(InstanceIdentifier input); + + @Override + public InstanceIdentifier deserialize(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ValueWithQName.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ValueWithQName.java new file mode 100644 index 0000000000..442df01327 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ValueWithQName.java @@ -0,0 +1,72 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import java.util.Map.Entry; + +import org.opendaylight.yangtools.yang.common.QName; + +public class ValueWithQName implements Entry{ + + final QName qname; + final V value; + + public ValueWithQName(QName qname, V value) { + super(); + this.qname = qname; + this.value = value; + } + + public QName getQname() { + return qname; + } + + public V getValue() { + return value; + } + + @Override + public QName getKey() { + return qname; + } + + @Override + public V setValue(V value) { + throw new UnsupportedOperationException(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((qname == null) ? 0 : qname.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + @SuppressWarnings("rawtypes") + ValueWithQName other = (ValueWithQName) obj; + if (qname == null) { + if (other.qname != null) + return false; + } else if (!qname.equals(other.qname)) + return false; + if (value == null) { + if (other.value != null) { + return false; + } + } else if (!value.equals(other.value)) { + return false; + } + return true; + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java new file mode 100644 index 0000000000..c2b5635af3 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java @@ -0,0 +1,7 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl; + +public interface BindingClassListener { + + void onBindingClassCaptured(Class cls); + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java new file mode 100644 index 0000000000..19e9961760 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java @@ -0,0 +1,79 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl; + +import java.lang.reflect.Field; +import java.util.Map; + +import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec; +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; + +public class CodecMapping { + + public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_CODEC"; + public static final String CLASS_TO_CASE_MAP = "CLASS_TO_CASE"; + public static final String COMPOSITE_TO_CASE = "COMPOSITE_TO_CASE"; + public static final String AUGMENTATION_CODEC = "AUGMENTATION_CODEC"; + + public static void setIdentifierCodec(Class obj,InstanceIdentifierCodec codec) { + Field instanceIdField; + try { + instanceIdField = obj.getField(INSTANCE_IDENTIFIER_CODEC); + instanceIdField.set(null, codec); + } catch (NoSuchFieldException e) { + // NOOP + } catch (SecurityException e) { + // NOOP + } catch (IllegalAccessException e) { + // NOOp + } + } + + public static void setClassToCaseMap(Class codec, + Map classToCaseRawCodec) { + Field instanceIdField; + try { + instanceIdField = codec.getField(CLASS_TO_CASE_MAP); + instanceIdField.set(null, classToCaseRawCodec); + } catch (NoSuchFieldException e) { + // NOOP + } catch (SecurityException e) { + // NOOP + } catch (IllegalAccessException e) { + // NOOp + } + + + } + + public static void setCompositeNodeToCaseMap(Class codec, + Map compositeToCase) { + Field instanceIdField; + try { + instanceIdField = codec.getField(COMPOSITE_TO_CASE); + instanceIdField.set(null, compositeToCase); + } catch (NoSuchFieldException e) { + // NOOP + } catch (SecurityException e) { + // NOOP + } catch (IllegalAccessException e) { + // NOOp + } + } + + public static void setAugmentationCodec(Class, Object>> dataCodec, + BindingCodec augmentableCodec) { + Field instanceIdField; + try { + instanceIdField = dataCodec.getField(AUGMENTATION_CODEC); + instanceIdField.set(null, augmentableCodec); + } catch (NoSuchFieldException e) { + // NOOP + } catch (SecurityException e) { + // NOOP + } catch (IllegalAccessException e) { + // NOOp + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecTypeUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecTypeUtils.java new file mode 100644 index 0000000000..048dc3ad47 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecTypeUtils.java @@ -0,0 +1,17 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl; + +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; + +public class CodecTypeUtils { + + @SuppressWarnings({"unchecked","rawtypes"}) + public static IdentifiableItem newIdentifiableItem(Class type, Object key) { + Class> identifiableType = (Class>) type; + Identifier> identifier = (Identifier>) key; + return new IdentifiableItem(identifiableType,identifier); + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java new file mode 100644 index 0000000000..3f74c9eaf4 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java @@ -0,0 +1,17 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl; + +import java.util.Map; + +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.common.QName; + +public interface GeneratorListener { + + + + void onCodecCreated(Class codec); + void onValueCodecCreated(Class valueClass,Class valueCodec); + void onChoiceCodecCreated(Class choiceClass,Class,Object>> choiceCodec); + void onCaseCodecCreated(Class choiceClass,Class,Object>> choiceCodec); + public abstract void onDataContainerCodecCreated(Class dataClass, Class,Object>> dataCodec); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend new file mode 100644 index 0000000000..fd02fde407 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend @@ -0,0 +1,123 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.controller.sal.binding.dom.serializer.api.CodecRegistry +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem +import org.opendaylight.yangtools.yang.common.QName +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item +import java.util.Map +import java.util.WeakHashMap +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates +import java.util.ArrayList +import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec +import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName +import java.util.HashMap +import org.slf4j.LoggerFactory +import java.util.List +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl +import org.opendaylight.yangtools.yang.data.api.Node +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import org.opendaylight.yangtools.yang.data.api.CompositeNode + +class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { + + private static val LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl); + val CodecRegistry codecRegistry; + + val Map,QName> classToQName = new WeakHashMap; + + + public new(CodecRegistry registry) { + codecRegistry = registry; + } + + + override deserialize(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input) { + var Class baType = null + val biArgs = input.path + val scannedPath = new ArrayList(biArgs.size); + val baArgs = new ArrayList(biArgs.size) + for(biArg : biArgs) { + scannedPath.add(biArg.nodeType); + val baArg = deserializePathArgument(biArg,scannedPath) + baArgs.add(baArg) + baType = baArg?.type + } + val ret = new InstanceIdentifier(baArgs,baType as Class); + return ret; + } + + private def dispatch org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifier argument,List processedPath) { + val Class cls = codecRegistry.getClassForPath(processedPath); + return new Item(cls); + } + + + private def dispatch org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifierWithPredicates argument,List processedPath) { + val Class type = codecRegistry.getClassForPath(processedPath); + val IdentifierCodec codec = codecRegistry.getIdentifierCodecForIdentifiable(type); + val value = codec.deserialize(argument.toCompositeNode())?.value; + return CodecTypeUtils.newIdentifiableItem(type,value); + } + + def CompositeNode toCompositeNode(NodeIdentifierWithPredicates predicates) { + val keyValues = predicates.keyValues.entrySet; + val values = new ArrayList>(keyValues.size) + for(keyValue : keyValues) { + values.add(new SimpleNodeTOImpl(keyValue.key,null,keyValue.value)) + } + return new CompositeNodeTOImpl(predicates.nodeType,null,values); + } + + override serialize(InstanceIdentifier input) { + val pathArgs = input.path as List + var QName previousQName = null; + val components = new ArrayList(pathArgs.size); + for(baArg : pathArgs) { + codecRegistry.bindingClassEncountered(baArg.type); + val biArg = serializePathArgument(baArg,previousQName); + previousQName = biArg.nodeType; + components.add(biArg); + } + return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(components); + } + + private def dispatch PathArgument serializePathArgument(Item argument, QName previousQname) { + val type = argument.type; + val qname = resolveQname(type); + if(previousQname == null) { + return new NodeIdentifier(qname); + } + return new NodeIdentifier(QName.create(previousQname,qname.localName)); + } + + private def dispatch PathArgument serializePathArgument(IdentifiableItem argument, QName previousQname) { + val Map predicates = new HashMap(); + val type = argument.type; + val keyCodec = codecRegistry.getIdentifierCodecForIdentifiable(type); + val qname = resolveQname(type); + val combinedInput = new ValueWithQName(previousQname,argument.key) + val compositeOutput = keyCodec.serialize(combinedInput as ValueWithQName); + for(outputValue :compositeOutput.value) { + predicates.put(outputValue.nodeType,outputValue.value); + } + if(previousQname == null) { + return new NodeIdentifierWithPredicates(qname,predicates); + } + return new NodeIdentifierWithPredicates(QName.create(previousQname,qname.localName),predicates); + } + + def resolveQname(Class class1) { + val qname = classToQName.get(class1); + if(qname !== null) { + return qname; + } + val qnameField = class1.getField("QNAME"); + val qnameValue = qnameField.get(null) as QName; + classToQName.put(class1,qnameValue); + } +} \ 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/IntermediateMapping.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend new file mode 100644 index 0000000000..d0b114e3c3 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend @@ -0,0 +1,40 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl + +import org.opendaylight.yangtools.yang.data.api.Node +import java.util.Map +import org.opendaylight.yangtools.yang.common.QName +import java.util.List +import java.util.ArrayList +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import com.google.common.base.Preconditions + +class IntermediateMapping { + + + + static def Node toNode(Map map) { + val nodeMap = map as Map; + Preconditions.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); + } +} \ 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/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java new file mode 100644 index 0000000000..e8e4c4375d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java @@ -0,0 +1,779 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.Set; +import java.util.WeakHashMap; + +import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec; +import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCaseCodec; +import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCodec; +import org.opendaylight.controller.sal.binding.dom.serializer.api.CodecRegistry; +import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec; +import org.opendaylight.controller.sal.binding.dom.serializer.api.DomCodec; +import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec; +import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec; +import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName; +import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener; +import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl; +import org.opendaylight.yangtools.binding.generator.util.Types; +import org.opendaylight.yangtools.concepts.Delegator; +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.yang.binding.Augmentable; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceNode; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.google.common.base.Preconditions.*; +import static org.opendaylight.controller.sal.binding.dom.serializer.impl.IntermediateMapping.*; + +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext; +import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType; +import org.opendaylight.yangtools.sal.binding.model.api.Type; +import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; + +public class LazyGeneratedCodecRegistry implements // + CodecRegistry, // + SchemaServiceListener, // + GeneratorListener { + + private final static Logger LOG = LoggerFactory.getLogger(LazyGeneratedCodecRegistry.class); + private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec(); + + private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this); + + private TransformerGenerator generator; + + // Concrete class to codecs + private Map, DataContainerCodec> containerCodecs = new WeakHashMap<>(); + private Map, IdentifierCodec> identifierCodecs = new WeakHashMap<>(); + private Map, ChoiceCodecImpl> choiceCodecs = new WeakHashMap<>(); + private Map, ChoiceCaseCodecImpl> caseCodecs = new WeakHashMap<>(); + private Map, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>(); + + /** Binding type to encountered classes mapping **/ + @SuppressWarnings("rawtypes") + Map> typeToClass = new ConcurrentHashMap<>(); + + @SuppressWarnings("rawtypes") + private ConcurrentMap typeToCaseNodes = new ConcurrentHashMap<>(); + + private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade(); + + Map pathToType = new ConcurrentHashMap<>(); + + private SchemaContext currentSchema; + + public TransformerGenerator getGenerator() { + return generator; + } + + public void setGenerator(TransformerGenerator generator) { + this.generator = generator; + } + + @Override + public InstanceIdentifierCodec getInstanceIdentifierCodec() { + return instanceIdentifierCodec; + } + + @Override + public > AugmentationCodec getCodecForAugmentation(Class object) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Class getClassForPath(List names) { + DataSchemaNode node = getSchemaNode(names); + SchemaPath path = node.getPath(); + GeneratedTypeBuilder type = pathToType.get(path); + ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); + @SuppressWarnings("rawtypes") + WeakReference weakRef = typeToClass.get(typeref); + return weakRef.get(); + } + + @Override + public IdentifierCodec getKeyCodecForPath(List names) { + @SuppressWarnings("unchecked") + Class> cls = (Class>) getClassForPath(names); + return getIdentifierCodecForIdentifiable(cls); + } + + @Override + public DataContainerCodec getCodecForDataObject(Class type) { + @SuppressWarnings("unchecked") + DataContainerCodec ret = (DataContainerCodec) containerCodecs.get(type); + if (ret != null) { + return ret; + } + Class, Object>> newType = generator.transformerFor(type); + BindingCodec, Object> rawCodec = newInstanceOf(newType); + DataContainerCodecImpl newWrapper = new DataContainerCodecImpl<>(rawCodec); + containerCodecs.put(type, newWrapper); + return newWrapper; + } + + @Override + @SuppressWarnings("rawtypes") + public void bindingClassEncountered(Class cls) { + ConcreteType typeRef = Types.typeForClass(cls); + WeakReference weakRef = new WeakReference<>(cls); + typeToClass.put(typeRef, weakRef); + } + + private DataSchemaNode getSchemaNode(List path) { + QName firstNode = path.get(0); + DataNodeContainer previous = currentSchema.findModuleByNamespaceAndRevision(firstNode.getNamespace(), + firstNode.getRevision()); + Iterator iterator = path.iterator(); + while (iterator.hasNext()) { + QName arg = iterator.next(); + DataSchemaNode currentNode = previous.getDataChildByName(arg); + if (currentNode == null && previous instanceof DataNodeContainer) { + currentNode = searchInChoices(previous, arg); + } + if (currentNode instanceof DataNodeContainer) { + previous = (DataNodeContainer) currentNode; + } else if (currentNode instanceof LeafSchemaNode || currentNode instanceof LeafListSchemaNode) { + checkState(!iterator.hasNext(), "Path tries to nest inside leaf node."); + return currentNode; + } + } + return (DataSchemaNode) previous; + } + + private DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) { + Set children = node.getChildNodes(); + for (DataSchemaNode child : children) { + if (child instanceof ChoiceNode) { + ChoiceNode choiceNode = (ChoiceNode) child; + DataSchemaNode potential = searchInCases(choiceNode, arg); + if (potential != null) { + return potential; + } + } + } + return null; + } + + private DataSchemaNode searchInCases(ChoiceNode choiceNode, QName arg) { + Set cases = choiceNode.getCases(); + for (ChoiceCaseNode caseNode : cases) { + DataSchemaNode node = caseNode.getDataChildByName(arg); + if (node != null) { + return node; + } + } + return null; + } + + private T newInstanceOf(Class newType) { + try { + @SuppressWarnings("unchecked") + T ret = (T) newType.newInstance(); + return ret; + } catch (InstantiationException e) { + throw new IllegalStateException(e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + + @Override + public > IdentifierCodec getIdentifierCodecForIdentifiable(Class type) { + IdentifierCodec obj = identifierCodecs.get(type); + if (obj != null) { + return obj; + } + Class, Object>> newCodec = generator + .keyTransformerForIdentifiable(type); + BindingCodec, Object> newInstance; + newInstance = newInstanceOf(newCodec); + IdentifierCodecImpl newWrapper = new IdentifierCodecImpl<>(newInstance); + identifierCodecs.put(type, newWrapper); + return newWrapper; + } + + @Override + public void onCodecCreated(Class cls) { + CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec); + } + + @Override + public > IdentifierCodec getCodecForIdentifier(Class object) { + @SuppressWarnings("unchecked") + IdentifierCodec obj = (IdentifierCodec) identifierCodecs.get(object); + if (obj != null) { + return obj; + } + Class, Object>> newCodec = generator + .keyTransformerForIdentifier(object); + BindingCodec, Object> newInstance; + newInstance = newInstanceOf(newCodec); + IdentifierCodecImpl newWrapper = new IdentifierCodecImpl<>(newInstance); + identifierCodecs.put(object, newWrapper); + return newWrapper; + } + + @SuppressWarnings("rawtypes") + public ChoiceCaseCodecImpl getCaseCodecFor(Class caseClass) { + ChoiceCaseCodecImpl potential = caseCodecs.get(caseClass); + if (potential != null) { + return potential; + } + ConcreteType typeref = Types.typeForClass(caseClass); + ChoiceCaseCodecImpl caseCodec = typeToCaseNodes.get(typeref); + + @SuppressWarnings("unchecked") + Class newCodec = generator.caseCodecFor(caseClass, caseCodec.schema); + BindingCodec newInstance = newInstanceOf(newCodec); + caseCodec.setDelegate(newInstance); + caseCodecs.put(caseClass, caseCodec); + + for (Entry, ChoiceCodecImpl> choice : choiceCodecs.entrySet()) { + if (choice.getKey().isAssignableFrom(caseClass)) { + choice.getValue().cases.put(caseClass, caseCodec); + } + } + return caseCodec; + } + + public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) { + pathToType.putAll(context.getChildNodes()); + + captureCases(context.getCases(), schemaContext); + } + + private void captureCases(Map cases, SchemaContext module) { + for (Entry caseNode : cases.entrySet()) { + ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode + .getValue().getName()); + ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey()); + @SuppressWarnings("rawtypes") + ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node); + typeToCaseNodes.putIfAbsent(typeref, value); + } + } + + @Override + public void onGlobalContextUpdated(SchemaContext context) { + currentSchema = context; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public void onChoiceCodecCreated(Class choiceClass, + Class, Object>> choiceCodec) { + ChoiceCodec oldCodec = choiceCodecs.get(choiceClass); + checkState(oldCodec == null); + BindingCodec, Object> delegate = newInstanceOf(choiceCodec); + ChoiceCodecImpl newCodec = new ChoiceCodecImpl(delegate); + choiceCodecs.put(choiceClass, newCodec); + CodecMapping.setClassToCaseMap(choiceCodec, (Map) classToCaseRawCodec); + CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase()); + + } + + @Override + public void onValueCodecCreated(Class valueClass, Class valueCodec) { + // TODO Auto-generated method stub + + } + + @Override + public void onCaseCodecCreated(Class choiceClass, + Class, Object>> choiceCodec) { + // TODO Auto-generated method stub + + } + + @Override + public void onDataContainerCodecCreated(Class dataClass, + Class, Object>> dataCodec) { + if (Augmentable.class.isAssignableFrom(dataClass)) { + AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass); + CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec); + } + + } + + private AugmentableCompositeCodec getAugmentableCodec(Class dataClass) { + AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass); + if (ret != null) { + return ret; + } + ret = new AugmentableCompositeCodec(dataClass); + augmentableCodecs.put(dataClass, ret); + return ret; + } + + private static abstract class IntermediateCodec implements // + DomCodec, Delegator, Object>> { + + private final BindingCodec, Object> delegate; + + @Override + public BindingCodec, Object> getDelegate() { + return delegate; + } + + public IntermediateCodec(BindingCodec, Object> delegate) { + this.delegate = delegate; + } + + @Override + public Node serialize(ValueWithQName input) { + Map intermediateOutput = delegate.serialize(input); + return toNode(intermediateOutput); + } + } + + private static class IdentifierCodecImpl> // + extends IntermediateCodec // + implements IdentifierCodec { + + public IdentifierCodecImpl(BindingCodec, Object> delegate) { + super(delegate); + } + + @Override + public ValueWithQName deserialize(Node input) { + QName qname = input.getNodeType(); + @SuppressWarnings("unchecked") + T value = (T) getDelegate().deserialize((Map) input); + return new ValueWithQName(qname, value); + } + + @Override + public CompositeNode serialize(ValueWithQName input) { + return (CompositeNode) super.serialize(input); + } + } + + private static class DataContainerCodecImpl // + extends IntermediateCodec // + implements DataContainerCodec { + + public DataContainerCodecImpl(BindingCodec, Object> delegate) { + super(delegate); + } + + @Override + public ValueWithQName deserialize(Node input) { + if (input == null) { + return null; + } + QName qname = input.getNodeType(); + @SuppressWarnings("unchecked") + T value = (T) getDelegate().deserialize((Map) input); + return new ValueWithQName(qname, value); + } + + @Override + public CompositeNode serialize(ValueWithQName input) { + return (CompositeNode) super.serialize(input); + } + } + + @SuppressWarnings("rawtypes") + private static class ChoiceCaseCodecImpl implements ChoiceCaseCodec, // + Delegator { + private final boolean augmenting; + private BindingCodec delegate; + + private final Set validNames; + private final Set validQNames; + private ChoiceCaseNode schema; + + public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) { + this.delegate = NOT_READY_CODEC; + this.schema = caseNode; + validNames = new HashSet<>(); + validQNames = new HashSet<>(); + for (DataSchemaNode node : caseNode.getChildNodes()) { + QName qname = node.getQName(); + validQNames.add(qname); + validNames.add(qname.getLocalName()); + } + augmenting = caseNode.isAugmenting(); + } + + @Override + public ValueWithQName deserialize(Node input) { + throw new UnsupportedOperationException("Direct invocation of this codec is not allowed."); + } + + @Override + public CompositeNode serialize(ValueWithQName input) { + throw new UnsupportedOperationException("Direct invocation of this codec is not allowed."); + } + + public BindingCodec getDelegate() { + return delegate; + } + + public void setDelegate(BindingCodec delegate) { + this.delegate = delegate; + } + + public ChoiceCaseNode getSchema() { + return schema; + } + + @Override + public boolean isAcceptable(Node input) { + if (false == (input instanceof CompositeNode)) { + if (augmenting) { + return checkAugmenting((CompositeNode) input); + } else { + return checkLocal((CompositeNode) input); + } + } + return false; + } + + private boolean checkLocal(CompositeNode input) { + QName parent = input.getNodeType(); + for (Node childNode : input.getChildren()) { + QName child = childNode.getNodeType(); + if (false == Objects.equals(parent.getNamespace(), child.getNamespace())) { + continue; + } + if (false == Objects.equals(parent.getRevision(), child.getRevision())) { + continue; + } + if (validNames.contains(child.getLocalName())) { + return true; + } + } + return false; + } + + private boolean checkAugmenting(CompositeNode input) { + for (Node child : input.getChildren()) { + if (validQNames.contains(child.getNodeType())) { + return true; + } + } + return false; + } + } + + private static class ChoiceCodecImpl implements ChoiceCodec { + + private final BindingCodec, Object> delegate; + + @SuppressWarnings("rawtypes") + private final Map> cases = new WeakHashMap<>(); + + private final CaseCompositeNodeMapFacade CompositeToCase; + + public ChoiceCodecImpl(BindingCodec, Object> delegate) { + this.delegate = delegate; + this.CompositeToCase = new CaseCompositeNodeMapFacade(cases); + } + + @Override + public ValueWithQName deserialize(Node input) { + throw new UnsupportedOperationException("Direct invocation of this codec is not allowed."); + } + + @Override + public Node serialize(ValueWithQName input) { + throw new UnsupportedOperationException("Direct invocation of this codec is not allowed."); + } + + public CaseCompositeNodeMapFacade getCompositeToCase() { + return CompositeToCase; + } + + public Map> getCases() { + return cases; + } + + public BindingCodec, Object> getDelegate() { + return delegate; + } + + } + + @SuppressWarnings("rawtypes") + private class CaseClassMapFacade extends MapFacadeBase { + + @Override + public Set>> entrySet() { + return null; + } + + @Override + public BindingCodec get(Object key) { + if (key instanceof Class) { + Class cls = (Class) key; + bindingClassEncountered(cls); + ChoiceCaseCodecImpl caseCodec = getCaseCodecFor(cls); + return caseCodec.getDelegate(); + } + return null; + } + } + + @SuppressWarnings("rawtypes") + private static class CaseCompositeNodeMapFacade extends MapFacadeBase { + + final Map> choiceCases; + + public CaseCompositeNodeMapFacade(Map> choiceCases) { + this.choiceCases = choiceCases; + } + + @Override + public Set> entrySet() { + return null; + } + + @Override + public BindingCodec get(Object key) { + if (false == (key instanceof CompositeNode)) { + return null; + } + for (java.util.Map.Entry> entry : choiceCases.entrySet()) { + ChoiceCaseCodecImpl codec = entry.getValue(); + if (codec.isAcceptable((CompositeNode) key)) { + return codec.getDelegate(); + } + } + return null; + } + } + + /** + * This map is used as only facade for {@link BindingCodec} in different + * classloaders to retrieve codec dynamicly based on provided key. + * + * @param + * Key type + */ + @SuppressWarnings("rawtypes") + private static abstract class MapFacadeBase implements Map { + + @Override + public boolean containsKey(Object key) { + return get(key) != null; + } + + @Override + public void clear() { + throw notModifiable(); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } + + @Override + public BindingCodec remove(Object key) { + return null; + } + + @Override + public int size() { + return 0; + } + + @Override + public Collection values() { + return null; + } + + private UnsupportedOperationException notModifiable() { + return new UnsupportedOperationException("Not externally modifiable."); + } + + @Override + public BindingCodec, Object> put(T key, BindingCodec value) { + throw notModifiable(); + } + + @Override + public void putAll(Map m) { + throw notModifiable(); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public Set keySet() { + return null; + } + + @Override + public Set> entrySet() { + return null; + } + + @Override + public boolean containsValue(Object value) { + return false; + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private class AugmentableCompositeCodec implements BindingCodec { + + private final Class augmentableType; + + Map rawAugmentationCodecs = new WeakHashMap<>(); + + public AugmentableCompositeCodec(Class type) { + checkArgument(Augmentable.class.isAssignableFrom(type)); + augmentableType = type; + } + + @Override + public Object serialize(Object input) { + if (input instanceof Augmentable) { + + Map augmentations = getAugmentations(input); + return serializeImpl(augmentations); + } + return null; + } + + private Map getAugmentations(Object input) { + Field augmentationField; + try { + augmentationField = input.getClass().getDeclaredField("augmentation"); + augmentationField.setAccessible(true); + Map augMap = (Map) augmentationField.get(input); + return augMap; + } catch (NoSuchFieldException e) { + + } catch (SecurityException e) { + + } catch (IllegalArgumentException e) { + + } catch (IllegalAccessException e) { + + } + return Collections.emptyMap(); + } + + private List serializeImpl(Map input) { + List ret = new ArrayList<>(); + for (Entry entry : input.entrySet()) { + BindingCodec codec = getRawCodecForAugmentation(entry.getKey()); + List output = (List) codec.serialize(new ValueWithQName(null, entry.getValue())); + ret.addAll(output); + } + return ret; + } + + private BindingCodec getRawCodecForAugmentation(Class key) { + BindingCodec ret = rawAugmentationCodecs.get(key); + if (ret != null) { + return ret; + } + try { + Class retClass = generator.augmentationTransformerFor(key); + ret = retClass.newInstance(); + rawAugmentationCodecs.put(key, ret); + return ret; + } catch (InstantiationException e) { + + } catch (IllegalAccessException e) { + + } + return null; + } + + @Override + public Map deserialize(Object input) { + Map ret = new HashMap<>(); + if (input instanceof CompositeNode) { + for (Entry codec : rawAugmentationCodecs.entrySet()) { + Augmentation value = (Augmentation) codec.getValue().deserialize(input); + if (value != null) { + ret.put(codec.getKey(), value); + } + } + } + return ret; + } + + public Map getRawAugmentationCodecs() { + return rawAugmentationCodecs; + } + + public void setRawAugmentationCodecs(Map rawAugmentationCodecs) { + this.rawAugmentationCodecs = rawAugmentationCodecs; + } + + public Class getAugmentableType() { + return augmentableType; + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static class LateMixinCodec implements BindingCodec, Delegator { + + private BindingCodec delegate; + + @Override + public BindingCodec getDelegate() { + if (delegate == null) { + throw new IllegalStateException("Codec not initialized yet."); + } + return delegate; + } + + @Override + public Object deserialize(Object input) { + return getDelegate().deserialize(input); + } + + @Override + public Object serialize(Object input) { + return getDelegate().serialize(input); + } + } +} \ 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/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend new file mode 100644 index 0000000000..4614c60ca1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend @@ -0,0 +1,218 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl + +import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator +import javassist.ClassPool +import org.opendaylight.yangtools.yang.model.api.SchemaContext +import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener +import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl +import java.util.Map +import org.opendaylight.yangtools.sal.binding.model.api.Type +import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder +import org.opendaylight.yangtools.yang.model.api.SchemaNode +import java.util.concurrent.ConcurrentHashMap +import org.opendaylight.yangtools.yang.data.api.CompositeNode +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import java.util.Map.Entry +import java.util.AbstractMap.SimpleEntry +import org.opendaylight.yangtools.yang.model.api.SchemaPath +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil +import java.util.ArrayList +import org.opendaylight.yangtools.yang.common.QName +import org.opendaylight.yangtools.yang.binding.DataContainer +import static com.google.common.base.Preconditions.*; +import java.util.List +import org.opendaylight.yangtools.yang.data.api.Node +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import org.opendaylight.yangtools.concepts.Delegator +import java.util.concurrent.ConcurrentMap +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType +import org.opendaylight.yangtools.yang.binding.BindingCodec +import com.google.common.collect.HashMultimap +import com.google.common.util.concurrent.SettableFuture +import java.util.concurrent.Future +import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl +import org.opendaylight.controller.sal.binding.dom.serializer.impl.LazyGeneratedCodecRegistry +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService +import org.slf4j.LoggerFactory +import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName +import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec +import org.opendaylight.yangtools.binding.generator.util.Types + +class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener { + + @Property + ClassPool pool; + + private static val LOG = LoggerFactory.getLogger(RuntimeGeneratedMappingServiceImpl); + + @Property + extension TransformerGenerator binding; + + @Property + extension LazyGeneratedCodecRegistry registry; + + @Property + val ConcurrentMap typeDefinitions = new ConcurrentHashMap(); + + @Property + val ConcurrentMap typeToDefinition = new ConcurrentHashMap(); + + @Property + val ConcurrentMap typeToSchemaNode = new ConcurrentHashMap(); + + val promisedTypeDefinitions = HashMultimap.>create; + + val promisedSchemas = HashMultimap.>create; + + override onGlobalContextUpdated(SchemaContext arg0) { + recreateBindingContext(arg0); + registry.onGlobalContextUpdated(arg0); + } + + def recreateBindingContext(SchemaContext schemaContext) { + val newBinding = new BindingGeneratorImpl(); + newBinding.generateTypes(schemaContext); + + for (entry : newBinding.moduleContexts.entrySet) { + + registry.onModuleContextAdded(schemaContext, entry.key, entry.value); + + //val module = entry.key; + val context = entry.value; + updateBindingFor(context.childNodes, schemaContext); + updateBindingFor(context.cases, schemaContext); + + + val typedefs = context.typedefs; + for (typedef : typedefs.values) { + binding.typeDefinitions.put(typedef, typedef as GeneratedType); + } + val augmentations = context.augmentations; + for (augmentation : augmentations) { + binding.typeToDefinition.put(augmentation, augmentation); + } + + binding.typeToAugmentation.putAll(context.typeToAugmentation); + } + } + + override CompositeNode toDataDom(DataObject data) { + toCompositeNodeImpl(data); + } + + override Entry toDataDom( + Entry, DataObject> entry) { + val key = toDataDom(entry.key) + val data = toCompositeNodeImpl(entry.value); + return new SimpleEntry(key, data); + } + + private def CompositeNode toCompositeNodeImpl(DataObject object) { + val cls = object.implementedInterface; + waitForSchema(cls); + val codec = registry.getCodecForDataObject(cls) as DataContainerCodec; + val ret = codec.serialize(new ValueWithQName(null, object)); + return ret as CompositeNode; + } + + private def waitForSchema(Class class1) { + val ref = Types.typeForClass(class1); + getSchemaWithRetry(ref); + } + + override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom( + InstanceIdentifier path) { + for (arg : path.path) { + waitForSchema(arg.type); + } + return registry.instanceIdentifierCodec.serialize(path); + } + + override dataObjectFromDataDom(InstanceIdentifier path, CompositeNode node) { + if (node == null) { + return null; + } + val targetType = path.targetType + val transformer = registry.getCodecForDataObject(targetType); + val ret = transformer.deserialize(node)?.value as DataObject; + return ret; + } + + private def void updateBindingFor(Map map, SchemaContext module) { + for (entry : map.entrySet) { + val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key); + //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName) + if (schemaNode != null) { + typeToSchemaNode.put(entry.value, schemaNode); + typeToDefinition.put(entry.value, entry.value); + updatePromisedSchemas(entry.value, schemaNode); + } + } + } + + public def void start() { + binding = new TransformerGenerator(pool); + registry = new LazyGeneratedCodecRegistry() + registry.generator = binding + + //binding.staticFieldsInitializer = registry + binding.listener = registry + binding.typeToDefinition = typeToDefinition + binding.typeToSchemaNode = typeToSchemaNode + binding.typeDefinitions = typeDefinitions + + } + + private def getTypeDefinition(Type type) { + val typeDef = typeToDefinition.get(type); + if (typeDef !== null) { + return typeDef; + } + return type.getTypeDefInFuture.get(); + } + + private def Future getTypeDefInFuture(Type type) { + val future = SettableFuture.create() + promisedTypeDefinitions.put(type, future); + return future; + } + + private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) { + val futures = promisedTypeDefinitions.get(builder); + if (futures === null || futures.empty) { + return; + } + for (future : futures) { + future.set(builder); + } + promisedTypeDefinitions.removeAll(builder); + } + + private def getSchemaWithRetry(Type type) { + val typeDef = typeToSchemaNode.get(type); + if (typeDef !== null) { + return typeDef; + } + return type.getSchemaInFuture.get(); + } + + private def Future getSchemaInFuture(Type type) { + val future = SettableFuture.create() + promisedSchemas.put(type, future); + return future; + } + + private def void updatePromisedSchemas(Type builder, SchemaNode schema) { + val ref = new ReferencedTypeImpl(builder.packageName, builder.name); + val futures = promisedSchemas.get(ref); + if (futures === null || futures.empty) { + return; + } + for (future : futures) { + future.set(schema); + } + promisedSchemas.removeAll(builder); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/StaticFieldInitializer.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/StaticFieldInitializer.java new file mode 100644 index 0000000000..e5b36e151a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/StaticFieldInitializer.java @@ -0,0 +1,6 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.impl; + +public interface StaticFieldInitializer { + + void initializeStaticFields(Class cls); +} 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 2136572aa3..8e059aa22e 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 @@ -9,9 +9,9 @@ import java.util.Map import org.opendaylight.yangtools.yang.common.QName import javassist.CtField import static javassist.Modifier.* +import static org.opendaylight.controller.sal.binding.dom.serializer.impl.CodecMapping.* 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 @@ -22,7 +22,6 @@ 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 @@ -31,13 +30,21 @@ 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 import org.opendaylight.controller.sal.binding.codegen.CodeGenerationException import org.opendaylight.yangtools.yang.model.api.ChoiceNode import java.security.ProtectionDomain import java.io.File +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty +import java.util.Map.Entry +import java.util.AbstractMap.SimpleEntry +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.yangtools.yang.binding.Augmentation +import java.util.Iterator +import org.opendaylight.yangtools.yang.model.api.AugmentationSchema +import java.util.concurrent.ConcurrentHashMap class TransformerGenerator { @@ -46,6 +53,7 @@ class 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 INSTANCE_IDENTIFIER = Types.typeForClass(InstanceIdentifier) //public static val DECIMAL = Types.typeForClass(Decimal); public static val LONG = Types.typeForClass(Long); @@ -53,36 +61,39 @@ class TransformerGenerator { val ClassPool classPool val extension JavassistUtils utils; - CtClass ctTransformator + CtClass BINDING_CODEC CtClass ctQName @Property var File classFileCapturePath; + @Property + var Map typeDefinitions = new ConcurrentHashMap(); @Property - var Map typeDefinitions; + var Map typeToDefinition = new ConcurrentHashMap(); @Property - var Map typeToDefinition + var Map typeToSchemaNode = new ConcurrentHashMap(); @Property - var Map typeToSchemaNode + var Map typeToAugmentation = new ConcurrentHashMap(); - val Map, Class> generatedClasses = new WeakHashMap(); + @Property + var GeneratorListener listener; public new(ClassPool pool) { classPool = pool; utils = new JavassistUtils(pool) - ctTransformator = BindingCodec.asCtClass; + BINDING_CODEC = BindingCodec.asCtClass; ctQName = QName.asCtClass } def Class, Object>> transformerFor(Class inputType) { - return withClassLoader(inputType.classLoader) [ | - val ret = generatedClasses.get(inputType); + return withClassLoaderAndLock(inputType.classLoader, lock) [ | + val ret = getGeneratedClass(inputType) if (ret !== null) { return ret as Class, Object>>; } @@ -90,60 +101,148 @@ class TransformerGenerator { val node = typeToSchemaNode.get(ref) val typeSpecBuilder = typeToDefinition.get(ref) val typeSpec = typeSpecBuilder.toInstance(); - val newret = generateTransformerFor(inputType, typeSpec, node) - generatedClasses.put(inputType, newret); + val newret = generateTransformerFor(inputType, typeSpec, node); + return newret as Class, Object>>; + ] + } + + def Class, Object>> augmentationTransformerFor(Class inputType) { + return withClassLoaderAndLock(inputType.classLoader, lock) [ | + val ret = getGeneratedClass(inputType) + if (ret !== null) { + return ret as Class, Object>>; + } + val ref = Types.typeForClass(inputType) + val node = typeToAugmentation.get(ref) + val typeSpecBuilder = typeToDefinition.get(ref) + val typeSpec = typeSpecBuilder.toInstance(); + val newret = generateAugmentationTransformerFor(inputType, typeSpec, node); + return newret as Class, Object>>; + ] + } + + def Class> caseCodecFor(Class inputType, ChoiceCaseNode node) { + return withClassLoaderAndLock(inputType.classLoader, lock) [ | + val ret = getGeneratedClass(inputType) + if (ret !== null) { + return ret as Class>; + } + val ref = Types.typeForClass(inputType) + val typeSpecBuilder = typeToDefinition.get(ref) + val typeSpec = typeSpecBuilder.toInstance(); + val newret = generateCaseCodec(inputType, typeSpec, node); + return newret as Class>; + ] + } + + def Class, Object>> keyTransformerForIdentifiable(Class parentType) { + return withClassLoaderAndLock(parentType.classLoader, lock) [ | + val inputName = parentType.name + "Key"; + val inputType = loadClassWithTCCL(inputName); + val ret = getGeneratedClass(inputType) + if (ret !== null) { + return ret as Class, Object>>; + } + val ref = Types.typeForClass(parentType) + val node = typeToSchemaNode.get(ref) as ListSchemaNode + val typeSpecBuilder = typeToDefinition.get(ref) + val typeSpec = typeSpecBuilder.identifierDefinition; + val newret = generateKeyTransformerFor(inputType, typeSpec, node); + return newret as Class, Object>>; + ] + } + + def getIdentifierDefinition(GeneratedTypeBuilder builder) { + val inst = builder.toInstance + val keyMethod = inst.methodDefinitions.findFirst[name == "getKey"] + return keyMethod.returnType as GeneratedTransferObject + } + + def Class, Object>> keyTransformerForIdentifier(Class inputType) { + return withClassLoaderAndLock(inputType.classLoader, lock) [ | + val ret = getGeneratedClass(inputType) + if (ret !== null) { + return ret as Class, Object>>; + } + val ref = Types.typeForClass(inputType) + val node = typeToSchemaNode.get(ref) as ListSchemaNode + val typeSpecBuilder = typeToDefinition.get(ref) + val typeSpec = typeSpecBuilder.toInstance(); + val newret = generateKeyTransformerFor(inputType, typeSpec, node); return newret as Class, Object>>; ] } private def Class keyTransformerFor(Class inputType, GeneratedType type, ListSchemaNode schema) { - return withClassLoader(inputType.classLoader) [ | - val transformer = generatedClasses.get(inputType); + return withClassLoaderAndLock(inputType.classLoader, lock) [ | + val transformer = getGeneratedClass(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) { + private def Class getGeneratedClass(Class cls) { + + try { + return loadClassWithTCCL(cls.codecClassName) + } catch (ClassNotFoundException e) { + return null; + } + } + + private 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); } private def Class getValueSerializer(GeneratedTransferObject type) { val cls = loadClassWithTCCL(type.resolvedName); - val transformer = generatedClasses.get(cls); + val transformer = cls.generatedClass; 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) + log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) val properties = typeSpec.allProperties; - val ctCls = createClass(inputType.transformatorFqn) [ + val ctCls = createClass(inputType.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) staticQNameField(node.QName); - implementsType(ctTransformator) + implementsType(BINDING_CODEC) method(Object, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC body = ''' { - - return null; + «QName.name» _resultName; + if($1 != null) { + _resultName = «QName.name».create($1,QNAME.getLocalName()); + } else { + _resultName = QNAME; + } + java.util.List _childNodes = new java.util.ArrayList(); + «inputType.name» value = («inputType.name») $2; + «FOR key : node.keyDefinition» + «val propertyName = key.getterName» + «val keyDef = node.getDataChildByName(key)» + «val property = properties.get(propertyName)» + «serializeProperty(keyDef, property, propertyName)»; + «ENDFOR» + return ($r) java.util.Collections.singletonMap(_resultName,_childNodes); } ''' ] @@ -160,7 +259,7 @@ class TransformerGenerator { «val propertyName = key.getterName» «val keyDef = node.getDataChildByName(key)» «val property = properties.get(propertyName)» - «deserializeProperty(keyDef, property.returnType, property)»; + «deserializeProperty(keyDef, property, propertyName)»; «ENDFOR» «inputType.name» _value = new «inputType.name»(«node.keyDefinition.keyConstructorList»); return _value; @@ -169,7 +268,12 @@ class TransformerGenerator { ] method(Object, "serialize", Object) [ body = ''' - return toDomStatic(QNAME,$1); + { + java.util.Map.Entry _input = (java.util.Map.Entry) $1; + «QName.name» _localQName = («QName.name») _input.getKey(); + «inputType.name» _keyValue = («inputType.name») _input.getValue(); + return toDomStatic(_localQName,_keyValue); + } ''' ] method(Object, "deserialize", Object) [ @@ -179,29 +283,95 @@ class TransformerGenerator { ] ] val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - log.info("DOM Codec for {} was generated {}",inputType,ret) + log.info("DOM Codec for {} was generated {}", inputType, ret) return ret as Class, ?>>; } catch (Exception e) { - processException(inputType,e); + processException(inputType, e); return null; } } - private def dispatch Class, Object>> generateTransformerFor(Class inputType, - GeneratedType typeSpec, SchemaNode node) { + private def Class> generateCaseCodec(Class inputType, GeneratedType type, + ChoiceCaseNode node) { try { - log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader) - val ctCls = createClass(typeSpec.transformatorFqn) [ + log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + val ctCls = createClass(type.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); + implementsType(BINDING_CODEC) staticQNameField(inputType); - implementsType(ctTransformator) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, AUGMENTATION_CODEC, BindingCodec) + method(Object, "toDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = ''' + { + «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) _childNodes; + } + ''' + ] + method(Object, "serialize", Object) [ + body = ''' + { + java.util.Map.Entry _input = (java.util.Map.Entry) $1; + «QName.name» _localName = QNAME; + if(_input.getKey() != null) { + _localName = («QName.name») _input.getKey(); + } + return toDomStatic(_localName,_input.getValue()); + } + ''' + ] + method(Object, "fromDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = deserializeBody(type, node) + ] + method(Object, "deserialize", Object) [ + body = ''' + { + + return fromDomStatic(QNAME,$1); + } + ''' + ] + ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.info("DOM Codec for {} was generated {}", inputType, ret) + return ret as Class>; + } catch (Exception e) { + processException(inputType, e); + return null; + } + } + + private def dispatch Class, Object>> generateTransformerFor( + Class inputType, GeneratedType typeSpec, SchemaNode node) { + try { + log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + val ctCls = createClass(typeSpec.codecClassName) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + staticQNameField(inputType); + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, AUGMENTATION_CODEC, BindingCodec) + implementsType(BINDING_CODEC) method(Object, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC body = serializeBodyFacade(typeSpec, node) ] method(Object, "serialize", Object) [ body = ''' - return toDomStatic(QNAME,$1); + { + java.util.Map.Entry _input = (java.util.Map.Entry) $1; + «QName.name» _localName = QNAME; + if(_input.getKey() != null) { + _localName = («QName.name») _input.getKey(); + } + return toDomStatic(_localName,_input.getValue()); + } ''' ] method(Object, "fromDomStatic", QName, Object) [ @@ -215,55 +385,159 @@ class TransformerGenerator { ] ] - val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - return ret as Class, Object>>; + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class, Object>> + listener?.onDataContainerCodecCreated(inputType, ret); + log.info("DOM Codec for {} was generated {}", inputType, ret) + return ret; } catch (Exception e) { - processException(inputType,e); + processException(inputType, e); return null; } } - - - private def dispatch Class, Object>> generateTransformerFor(Class inputType, - GeneratedType typeSpec, ChoiceNode node) { + + private def Class, Object>> generateAugmentationTransformerFor( + Class inputType, GeneratedType type, AugmentationSchema node) { try { - log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader) - val ctCls = createClass(typeSpec.transformatorFqn) [ + log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + val properties = type.allProperties + val ctCls = createClass(type.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); - //staticQNameField(inputType); - implementsType(ctTransformator) + staticQNameField(inputType); + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, AUGMENTATION_CODEC, BindingCodec) + implementsType(BINDING_CODEC) method(Object, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC body = ''' - return null; + { + //System.out.println("Qname " + $1); + //System.out.println("Value " + $2); + «QName.name» _resultName = «QName.name».create($1,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»()); + «serializeProperty(child, signature.value, signature.key)» + «ENDFOR» + return ($r) _childNodes; + } ''' ] method(Object, "serialize", Object) [ body = ''' - return null; + { + java.util.Map.Entry _input = (java.util.Map.Entry) $1; + «QName.name» _localName = QNAME; + if(_input.getKey() != null) { + _localName = («QName.name») _input.getKey(); + } + return toDomStatic(_localName,_input.getValue()); + } ''' ] method(Object, "fromDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC body = ''' - return null; + { + «QName.name» _localQName = QNAME; + + if($2 == null) { + return null; + } + java.util.Map _compositeNode = (java.util.Map) $2; + ////System.out.println(_localQName + " " + _compositeNode); + «type.builderName» _builder = new «type.builderName»(); + «FOR child : node.childNodes» + «val signature = properties.getFor(child)» + «deserializeProperty(child, signature.value, signature.key)» + + _builder.«signature.key.toSetter»(«signature.key»); + «ENDFOR» + return _builder.build(); + } ''' ] method(Object, "deserialize", Object) [ body = ''' - return null; + return fromDomStatic(QNAME,$1); ''' ] ] - val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - return ret as Class, Object>>; + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class, Object>> + listener?.onDataContainerCodecCreated(inputType, ret); + return ret; } catch (Exception e) { - processException(inputType,e); + processException(inputType, e); + return null; + } + } + + private def dispatch Class, Object>> generateTransformerFor( + Class inputType, GeneratedType typeSpec, ChoiceNode node) { + try { + log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + val ctCls = createClass(typeSpec.codecClassName) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + //staticQNameField(inputType); + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, CLASS_TO_CASE_MAP, Map) + staticField(it, COMPOSITE_TO_CASE, Map) + //staticField(it,QNAME_TO_CASE_MAP,BindingCodec) + implementsType(BINDING_CODEC) + method(List, "toDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + body = ''' + { + if($2 == null) { + return null; + } + «DataObject.name» _baValue = («DataObject.name») $2; + Class _baClass = _baValue.getImplementedInterface(); + «BINDING_CODEC.name» _codec = «CLASS_TO_CASE_MAP».get(_baClass); + if(_codec == null) { + return null; + } + java.util.Map.Entry _input = new «SimpleEntry.name»($1,_baValue); + return (java.util.List) _codec.serialize(_input); + } + ''' + ] + method(Object, "serialize", Object) [ + body = ''' + throw new «UnsupportedOperationException.name»("Direct invocation not supported."); + ''' + ] + method(Object, "fromDomStatic", QName, Map) [ + modifiers = PUBLIC + FINAL + STATIC + body = ''' + { + «BINDING_CODEC.name» _codec = («BINDING_CODEC.name») «COMPOSITE_TO_CASE».get($2); + if(_codec != null) { + return _codec.deserialize(new «SimpleEntry.name»($1,$2)); + } + return null; + } + ''' + ] + method(Object, "deserialize", Object) [ + body = ''' + throw new «UnsupportedOperationException.name»("Direct invocation not supported."); + ''' + ] + ] + + val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + val ret = rawRet as Class, Object>>; + listener?.onChoiceCodecCreated(inputType, ret); + log.info("DOM Codec for {} was generated {}", inputType, ret) + return ret; + } catch (Exception e) { + processException(inputType, e); return null; } } - private def keyConstructorList(List qnames) { val names = new TreeSet() @@ -302,7 +576,6 @@ class TransformerGenerator { } java.util.Map _compositeNode = (java.util.Map) $2; «type.builderName» _builder = new «type.builderName»(); - return _builder.build(); } ''' @@ -317,6 +590,7 @@ class TransformerGenerator { «type.builderName» _builder = new «type.builderName»(); «deserializeKey(type, node)» «deserializeDataNodeContainerBody(type, node)» + «deserializeAugmentations» return _builder.build(); } ''' @@ -330,6 +604,7 @@ class TransformerGenerator { java.util.Map _compositeNode = (java.util.Map) $2; «type.builderName» _builder = new «type.builderName»(); «deserializeDataNodeContainerBody(type, node)» + «deserializeAugmentations» return _builder.build(); } ''' @@ -337,12 +612,15 @@ class TransformerGenerator { 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; + ////System.out.println(_localQName + " " + _compositeNode); «type.builderName» _builder = new «type.builderName»(); «deserializeDataNodeContainerBody(type, node)» + «deserializeAugmentations» return _builder.build(); } ''' @@ -351,87 +629,106 @@ class TransformerGenerator { deserializeNodeContainerBodyImpl(type, type.allProperties, node); } - private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap properties, + private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap properties, DataNodeContainer node) { val ret = ''' «FOR child : node.childNodes.filter[!augmenting]» «val signature = properties.getFor(child)» - «deserializeProperty(child, signature.returnType, signature)» - _builder.«signature.name.toSetter»(«signature.name»); + «deserializeProperty(child, signature.value, signature.key)» + + _builder.«signature.key.toSetter»(«signature.key»); «ENDFOR» ''' return ret; } + def deserializeAugmentations() ''' + java.util.Map _augmentation = (java.util.Map) «AUGMENTATION_CODEC».deserialize(_compositeNode); + if(_augmentation != null) { + «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()); + Class _type = (Class) _entry.getKey(); + «Augmentation.resolvedName» _value = («Augmentation.name») _entry.getValue(); + _builder.addAugmentation(_type,_value); + } + } + ''' + 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. + String propertyName) ''' + java.util.List _dom_«propertyName» = _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) { + ////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(); - java.util.Iterator _iterator = _dom_«property.name».iterator(); + java.util.Iterator _iterator = _dom_«propertyName».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); + ////System.out.println(" item" + _listItem); + Object _value = «type.actualTypeArguments.get(0).serializer.resolvedName».fromDomStatic(_localQName,_listItem); + ////System.out.println(" value" + _value); + «propertyName».add(_value); _hasNext = _iterator.hasNext(); } } - //System.out.println(" list" + «property.name»); + ////System.out.println(" list" + «propertyName»); ''' 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. + String propertyName) ''' + java.util.List _dom_«propertyName» = _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 «propertyName» = new java.util.ArrayList(); + if(_dom_«propertyName» != null) { java.util.List _serialized = new java.util.ArrayList(); - java.util.Iterator _iterator = _dom_«property.name».iterator(); + java.util.Iterator _iterator = _dom_«propertyName».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); + «propertyName».add(_value); } _hasNext = _iterator.hasNext(); } } ''' - private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, MethodSignature property) ''' - java.util.List _dom_«property.name»_list = + private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, String propertyName) ''' + java.util.List _dom_«propertyName»_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")»; + «type.resolvedName» «propertyName» = null; + if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) { + 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")»; } ''' private def dispatch CharSequence deserializeProperty(ContainerSchemaNode schema, Type type, - MethodSignature property) ''' - java.util.List _dom_«property.name»_list = + String propertyName) ''' + java.util.List _dom_«propertyName»_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) { + «type.resolvedName» «propertyName» = null; + if(_dom_«propertyName»_list != null && _dom_«propertyName»_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»); + java.util.Map _dom_«propertyName» = (java.util.Map) _dom_«propertyName»_list.get(0); + «propertyName» = «type.serializer.resolvedName».fromDomStatic(_localQName,_dom_«propertyName»); } ''' + private def dispatch CharSequence deserializeProperty(ChoiceNode schema, Type type, String propertyName) ''' + «type.resolvedName» «propertyName» = «type.serializer.resolvedName».fromDomStatic(_localQName,_compositeNode); + ''' + private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter) ''' - («type.resolvedName») «type.valueSerializer.name».fromDomValue(«domParameter»); + («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter»); ''' private def dispatch Class, Object>> generateValueTransformer( @@ -445,9 +742,10 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) return ret as Class, Object>>; } - val ctCls = createClass(typeSpec.transformatorFqn) [ + val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); - implementsType(ctTransformator) + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) implementsType(BindingDeserializer.asCtClass) method(Object, "toDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC @@ -459,10 +757,11 @@ class TransformerGenerator { 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); - return _value; + ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value); + Object _domValue = «serializeValue(returnType, "_value")»; + return _domValue; } ''' ] @@ -477,7 +776,7 @@ class TransformerGenerator { modifiers = PUBLIC + FINAL + STATIC body = ''' { - //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1); if($1 == null) { return null; @@ -497,10 +796,10 @@ class TransformerGenerator { ] val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - log.info("DOM Codec for {} was generated {}",inputType,ret) + log.info("DOM Codec for {} was generated {}", inputType, ret) return ret as Class, Object>>; } catch (Exception e) { - log.error("Cannot compile DOM Codec for {}",inputType,e); + log.error("Cannot compile DOM Codec for {}", inputType, e); val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType); exception.addSuppressed(e); throw exception; @@ -509,10 +808,10 @@ class TransformerGenerator { } private def createDummyImplementation(Class object, GeneratedTransferObject typeSpec) { - log.info("Generating Dummy DOM Codec for {} with {}",object,object.classLoader) - return createClass(typeSpec.transformatorFqn) [ + log.info("Generating Dummy DOM Codec for {} with {}", object, object.classLoader) + return createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); - implementsType(ctTransformator) + implementsType(BINDING_CODEC) implementsType(BindingDeserializer.asCtClass) method(Object, "toDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC @@ -553,10 +852,10 @@ class TransformerGenerator { 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) [ + log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); - implementsType(ctTransformator) + implementsType(BINDING_CODEC) method(Object, "toDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC body = ''' @@ -591,49 +890,57 @@ class TransformerGenerator { ] val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - log.info("DOM Codec for {} was generated {}",inputType,ret) + log.info("DOM Codec for {} was generated {}", inputType, ret) return ret as Class, Object>>; } catch (CodeGenerationException e) { - throw new CodeGenerationException("Cannot compile Transformator for " + inputType,e); + throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e); } catch (Exception e) { - log.error("Cannot compile DOM Codec for {}",inputType,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 Class toClassImpl(CtClass newClass, ClassLoader loader, ProtectionDomain domain) { - val cls = newClass.toClass(loader,domain); - if(classFileCapturePath !== null) { + val cls = newClass.toClass(loader, domain); + if (classFileCapturePath !== null) { newClass.writeFile(classFileCapturePath.absolutePath); } + listener?.onCodecCreated(cls); return cls; } - + def debugWriteClass(CtClass class1) { - val path = class1.name.replace(".","/")+".class" - - val captureFile = new File(classFileCapturePath,path); + val path = class1.name.replace(".", "/") + ".class" + + val captureFile = new File(classFileCapturePath, path); captureFile.createNewFile - - + } - private def dispatch String deserializeValue(Type type, String domParameter) '''(«type.resolvedName») «domParameter»''' + private def dispatch String deserializeValue(Type type, String domParameter) { + if (INSTANCE_IDENTIFIER.equals(type)) { + + return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)''' + } + + return '''(«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, Type type, String propertyName) ''' + «type.resolvedName» «propertyName» = null; ''' private def dispatch CharSequence deserializeProperty(DataSchemaNode container, GeneratedTypeBuilder type, - MethodSignature property) { - _deserializeProperty(container, type.toInstance, property) + String propertyName) { + _deserializeProperty(container, type.toInstance, propertyName) } public static def toSetter(String it) { @@ -647,84 +954,96 @@ class TransformerGenerator { } /* - 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 dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); + if(«propertyName» != null) { + Object domValue = «type.serializer».toDomStatic(QNAME,«propertyName»); + _childNodes.add(domValue); } ''' */ private def getBuilderName(GeneratedType type) '''«type.resolvedName»Builder''' - private def staticQNameField(CtClass it, Class node) { + 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»")''') + 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(); + «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); + «serializeAugmentations» + 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(); + «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); + «serializeAugmentations» + return ($r) java.util.Collections.singletonMap(_resultName,_childNodes); } ''' private def dispatch String serializeBody(GeneratedType type, ChoiceCaseNode node) ''' { - «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName()); - java.util.List childNodes = new java.util.ArrayList(); + «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); + «serializeAugmentations» + return ($r) java.util.Collections.singletonMap(_resultName,_childNodes); } ''' private def dispatch String serializeBody(GeneratedType type, SchemaNode node) ''' { - «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName()); - java.util.List childNodes = new java.util.ArrayList(); + «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName()); + java.util.List _childNodes = new java.util.ArrayList(); «type.resolvedName» value = («type.resolvedName») $2; - return ($r) java.util.Collections.singletonMap(resultName,childNodes); + return ($r) java.util.Collections.singletonMap(_resultName,_childNodes); } ''' - - private def transformDataContainerBody(Map properties, DataNodeContainer node) { + private def transformDataContainerBody(Map properties, DataNodeContainer node) { val ret = ''' «FOR child : node.childNodes.filter[!augmenting]» «var signature = properties.getFor(child)» - «serializeProperty(child, signature.returnType, signature)» + //System.out.println("«signature.key»" + value.«signature.key»()); + «serializeProperty(child, signature.value, signature.key)» «ENDFOR» ''' return ret; } - - def MethodSignature getFor(Map map, DataSchemaNode node) { + + def serializeAugmentations() ''' + java.util.List _augmentations = (java.util.List) «AUGMENTATION_CODEC».serialize(value); + if(_augmentations != null) { + _childNodes.addAll(_augmentations); + } + ''' + + def Entry getFor(Map map, DataSchemaNode node) { val sig = map.get(node.getterName); - if(sig == null) { - return map.get(node.booleanGetterName); + if (sig == null) { + + return new SimpleEntry(node.booleanGetterName, map.get(node.booleanGetterName)); } - return sig; + return new SimpleEntry(node.getterName, sig); } private static def String getBooleanGetterName(DataSchemaNode node) { @@ -740,106 +1059,126 @@ class TransformerGenerator { } 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(); + String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); + if(«propertyName» != null) { + java.util.Iterator _iterator = «propertyName».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); + Object _domValue = «type.actualTypeArguments.get(0).serializer.resolvedName».toDomStatic(_resultName,_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»(); + private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); - if(«property.name» != null) { - «QName.name» _qname = «QName.name».create(resultName,"«schema.QName.localName»"); - Object _propValue = «serializeValue(type, property.name)»; + if(«propertyName» != null) { + «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»"); + Object _propValue = «serializeValue(type, propertyName)»; if(_propValue != null) { Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); - childNodes.add(_domValue); + _childNodes.add(_domValue); } } ''' - private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.name».toDomValue(«parameter»)''' + private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer. + resolvedName».toDomValue(«parameter»)''' - private def dispatch serializeValue(Type signature, String property) '''«property»''' + private def dispatch serializeValue(Type signature, String property) { + if (INSTANCE_IDENTIFIER == signature) { + return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)''' + } + return '''«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(); + private def dispatch CharSequence serializeProperty(LeafListSchemaNode schema, ParameterizedType type, + String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); + if(«propertyName» != null) { + «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»"); + java.util.Iterator _iterator = «propertyName».iterator(); boolean _hasNext = _iterator.hasNext(); while(_hasNext) { Object _listItem = _iterator.next(); - Object _propValue = «property.name»; + Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem")»; Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); - childNodes.add(_domValue); + _childNodes.add(_domValue); _hasNext = _iterator.hasNext(); } } ''' + private def dispatch CharSequence serializeProperty(ChoiceNode container, GeneratedType type, + String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); + if(«propertyName» != null) { + java.util.List domValue = «type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»); + _childNodes.addAll(domValue); + } + ''' + /** * 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, Type type, String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); + if(«propertyName» != null) { + Object domValue = «propertyName»; + _childNodes.add(domValue); } ''' private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedTypeBuilder type, - MethodSignature property) { - serializeProperty(container, type.toInstance, property) + String propertyName) { + serializeProperty(container, type.toInstance, propertyName) } 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.name».toDomStatic(QNAME,«property.name»); - childNodes.add(domValue); + String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); + if(«propertyName» != null) { + Object domValue = «type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»); + _childNodes.add(domValue); } ''' - - - private def transformatorFqn(GeneratedType typeSpec) { + private def codecClassName(GeneratedType typeSpec) { return '''«typeSpec.resolvedName»$Broker$Codec$DOM''' } - private def transformatorFqn(Class typeSpec) { + private def codecClassName(Class typeSpec) { return '''«typeSpec.name»$Broker$Codec$DOM''' } - private def HashMap getAllProperties(GeneratedType type) { - val ret = new HashMap(); + private def dispatch HashMap getAllProperties(GeneratedType type) { + val ret = new HashMap(); type.collectAllProperties(ret); return ret; } - private def dispatch void collectAllProperties(GeneratedType type, Map set) { + private def dispatch void collectAllProperties(GeneratedType type, Map set) { for (definition : type.methodDefinitions) { - set.put(definition.name, definition); + set.put(definition.name, definition.returnType); + } + for (property : type.properties) { + set.put(property.getterName, property.returnType); } - for (parent : type.implements) { parent.collectAllProperties(set); } } - private def dispatch void collectAllProperties(Type type, Map set) { + def String getGetterName(GeneratedProperty property) { + return "get" + property.name.toFirstUpper + } + + private def dispatch void collectAllProperties(Type type, Map set) { // NOOP for generic type. } @@ -847,22 +1186,24 @@ class TransformerGenerator { return type.asCtClass.name; } + def String getResolvedName(Class type) { + return type.asCtClass.name; + } + def CtClass asCtClass(Type type) { val name = type.fullyQualifiedName val cls = loadClassWithTCCL(type.fullyQualifiedName) return cls.asCtClass; } - - - - private def dispatch processException(Class inputType,CodeGenerationException e){ - log.error("Cannot compile DOM Codec for {}. One of it's prerequisites was not generated.",inputType); + + private def dispatch processException(Class inputType, CodeGenerationException e) { + log.error("Cannot compile DOM Codec for {}. One of it's prerequisites was not generated.", inputType); throw e; } - - private def dispatch processException(Class inputType,Exception e){ - log.error("Cannot compile DOM Codec for {}",inputType,e); - val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType,e); + + private def dispatch processException(Class inputType, Exception e) { + log.error("Cannot compile DOM Codec for {}", inputType, e); + val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType, e); throw exception; } @@ -876,7 +1217,7 @@ class PropertyPair { Type type; @Property - MethodSignature signature; + Type returnType; @Property SchemaNode schemaNode; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend index 6e493057b2..887ef82ca9 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend @@ -179,7 +179,7 @@ class NotifyTask implements Callable { try { listener.onNotification(notification); } catch (Exception e) { - log.error("Unhandled exception {} thrown by listener: {} Notification: {}", e, listener, notification); + log.error("Unhandled exception thrown by listener: {}", listener, e); } return null; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java index d8fbc70f8e..8e61c9b3ee 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom; import java.util.Map.Entry; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -16,4 +17,6 @@ public interface BindingIndependentMappingService { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(InstanceIdentifier path); DataObject dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result); + + } 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 deleted file mode 100644 index a0e1c98237..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend +++ /dev/null @@ -1,455 +0,0 @@ -package org.opendaylight.controller.sal.binding.impl.connect.dom - -import org.opendaylight.yangtools.yang.common.QName -import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext -import java.util.List -import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder -import org.opendaylight.yangtools.sal.binding.model.api.Type -import org.opendaylight.yangtools.yang.model.api.SchemaNode -import java.util.Map -import org.opendaylight.yangtools.yang.model.api.SchemaPath -import org.opendaylight.yangtools.yang.model.api.SchemaContext -import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil -import org.opendaylight.yangtools.binding.generator.util.Types -import java.util.HashMap -import org.opendaylight.yangtools.yang.data.api.CompositeNode -import org.opendaylight.yangtools.yang.binding.DataContainer -import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl -import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty -import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType -import java.util.Collections -import java.util.ArrayList -import org.opendaylight.yangtools.yang.data.api.Node -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode -import org.opendaylight.yangtools.yang.model.api.DataNodeContainer -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode -import org.opendaylight.yangtools.yang.model.api.ChoiceNode -import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode -import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl -import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl -import org.opendaylight.yangtools.yang.model.api.NotificationDefinition -import org.opendaylight.yangtools.yang.model.api.TypeDefinition -import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition -import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates -import org.opendaylight.yangtools.yang.model.util.ExtendedType -import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject -import com.google.common.collect.FluentIterable -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) { - val ref = Types.typeForClass(cls); - return typeToSchemaNode.get(ref)?.QName; - } - - def void updateBinding(SchemaContext schemaContext, ModuleContext moduleBindingContext) { - updateBindingFor(moduleBindingContext.childNodes, schemaContext); - - } - - def org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom( - InstanceIdentifier obj) { - val pathArguments = obj.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); - } - - - - def DataObject dataObjectFromDataDom(InstanceIdentifier identifier, CompositeNode node) { - if (node == null) { - return null; - } - val targetClass = identifier.targetType; - val classLoader = targetClass.classLoader; - val ref = Types.typeForClass(targetClass); - val targetType = typeToDefinition.get(ref); - val targetSchema = typeToSchemaNode.get(ref); - return node.toDataObject(classLoader, targetType.toInstance, targetSchema); - - } - - 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 dispatch PathArgument toDataDomPathArgument(Item argument, Class parent) { - val ref = Types.typeForClass(argument.type); - val qname = typeToSchemaNode.get(ref).QName - return new NodeIdentifier(qname); - } - - 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 = identifier.getSimpleValue(keydef, keyNode.type); - map.put(keydef, value.value); - } - return map; - } - - 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) - } - } - - def CompositeNode toCompositeNode(DataContainer data) { - val type = data.implementedInterface; - val typeRef = Types.typeForClass(type); - val schemaNode = typeToSchemaNode.get(typeRef); - val generatedType = typeToDefinition.get(typeRef); - - return data.toDataDom(schemaNode, generatedType); - } - - private def dispatch CompositeNode toDataDom(DataContainer data, ContainerSchemaNode node, - GeneratedTypeBuilder builder) { - val subnodes = data.toDataDomComponents(node); - return new CompositeNodeTOImpl(node.QName, null, subnodes); - } - - private def dispatch CompositeNode toDataDom(DataContainer data, NotificationDefinition node, - GeneratedTypeBuilder builder) { - val subnodes = data.toDataDomComponents(node); - return new CompositeNodeTOImpl(node.QName, null, subnodes); - } - - private def dispatch CompositeNode toDataDom(DataContainer data, ListSchemaNode node, - GeneratedTypeBuilder builder) { - val subnodes = data.toDataDomComponents(node); - return new CompositeNodeTOImpl(node.QName, null, subnodes); - } - - private def List> toDataDomComponents(DataContainer data, DataNodeContainer node) { - val subnodes = new ArrayList>(); - for (childNode : node.childNodes) { - val value = childNode.dataDomFromParent(data); - if (value !== null) { - subnodes.addAll(value); - } - } - return subnodes; - } - - private def List> dataDomFromParent(DataSchemaNode node, DataContainer container) { - if (node.augmenting) { - return Collections.emptyList(); - } - return dataDomFromParentImpl(node, container); - } - - private def dispatch List> dataDomFromParentImpl(LeafSchemaNode node, DataContainer container) { - val value = container.getSimpleValue(node.QName, node.type); - if (value !== null) { - return Collections.>singletonList(value); - } - return Collections.emptyList(); - } - - private def dispatch List> dataDomFromParentImpl(LeafListSchemaNode node, DataContainer container) { - val values = container.getSimpleValues(node); - if (values !== null) { - //val it = new ArrayList>(); - //for (value : values) { - //} - - } - return Collections.emptyList(); - } - - private def getSimpleValues(DataContainer container, LeafListSchemaNode node) { - return Collections.emptyList(); - } - - private def dispatch List> dataDomFromParentImpl(ListSchemaNode node, DataContainer container) { - val qname = node.QName; - val values = container.getValue(qname, List) as List; - if (values === null) { - return Collections.emptyList; - } - val it = new ArrayList>(); - for (value : values) { - add(value.toCompositeNode()); - } - - return it; - } - - private def dispatch List> dataDomFromParentImpl(ChoiceNode node, DataContainer container) { - } - - private def dispatch List> serializeValueImpl(List list, GeneratedTypeBuilder builder, - ListSchemaNode node) { - val it = new ArrayList>(); - for (value : list) { - - val serVal = value.serializeValueImpl(builder, node); - if (serVal !== null) { - addAll(serVal); - } - } - return it; - } - - public static def dispatch Node getSimpleValue(Object container, QName name, ExtendedType type) { - getSimpleValue(container, name, type.baseType); - } - - 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); - } - - 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); - } - - 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); - } - - 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); - } - - 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) { - clz = (object as DataContainer).implementedInterface; - } - val method = clz.getMethod(methodName); - if (method === null) { - return null; - } - val value = method.invoke(object); - if (value === null) { - return null; - } - if (type.isAssignableFrom(value.class)) { - return value as T; - } - return value.getEncapsulatedValue(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; - } - return null; - } - - private def dispatch List> serializeValueImpl(DataContainer data, GeneratedTypeBuilder builder, - SchemaNode node) { - return Collections.>singletonList(data.toDataDom(node, builder)); - } - - private def dispatch List> serializeValueImpl(Object object, GeneratedTypeBuilder builder, - SchemaNode node) { - } - - def DataObject toDataObject(CompositeNode node, ClassLoader loader, GeneratedType type, SchemaNode schema) { - - // Nasty reflection hack (for now) - val builderClass = loader.loadClass(type.builderFQN); - val builder = builderClass.newInstance; - val buildMethod = builderClass.getMethod("build"); - - node.fillDataObject(builder, loader, type, schema); - - return buildMethod.invoke(builder) as DataObject; - } - - private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, - ListSchemaNode schema) { - - if (schema.keyDefinition !== null && !schema.keyDefinition.empty) { - - val value = node.keyToBindingKey(loader, type, schema); - builder.setProperty("key", value); - } - node.fillBuilderFromContainer(builder,loader,type,schema); - } - - - - private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, - ContainerSchemaNode schema) { - node.fillBuilderFromContainer(builder,loader,type,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; - val args = new ArrayList(); - for (key : schema.keyDefinition) { - var keyProperty = keyType.get(BindingGeneratorUtil.parseToClassName(key.localName)); - if (keyProperty == null) { - keyProperty = keyType.get(BindingGeneratorUtil.parseToValidParamName(key.localName)); - } - val domKeyValue = node.getFirstSimpleByName(key); - val keyValue = domKeyValue.deserializeSimpleValue(loader, keyProperty.returnType, - schema.getDataChildByName(key)); - args.add(keyValue); - } - return ClassLoaderUtils.construct(constructor, args); - } - - private def dispatch Object deserializeSimpleValue(SimpleNode node, ClassLoader loader, Type type, - LeafSchemaNode node2) { - deserializeSimpleValueImpl(node, loader, type, node2.type); - } - - private def dispatch Object deserializeSimpleValue(SimpleNode node, ClassLoader loader, Type type, - LeafListSchemaNode node2) { - deserializeSimpleValueImpl(node, loader, type, node2.type); - } - - private def dispatch Object deserializeSimpleValueImpl(SimpleNode node, ClassLoader loader, Type type, - ExtendedType definition) { - deserializeSimpleValueImpl(node, loader, type, definition.baseType); - } - - private def dispatch Object deserializeSimpleValueImpl(SimpleNode node, ClassLoader loader, Type type, - StringTypeDefinition definition) { - if (type instanceof GeneratedTransferObject) { - val cls = loader.getClassForType(type); - val const = cls.getConstructor(String); - val str = String.valueOf(node.value); - return const.newInstance(str); - } - return node.value; - } - - private def Class getClassForType(ClassLoader loader, Type type) { - loader.loadClass(type.fullyQualifiedName); - } - - private def dispatch Object deserializeSimpleValueImpl(SimpleNode node, ClassLoader loader, Type type, - TypeDefinition definition) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - 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(); - for (prop : key.properties) { - ret.put(prop.name, prop); - } - return ret; - } - - 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); - } - - private def String getBuilderFQN(Type type) '''«type.fullyQualifiedName»Builder''' - - private def String getKeyFQN(Type type) '''«type.fullyQualifiedName»Key''' - -} - -@Data -class PropertyCapture { - - @Property - val Type returnType; - @Property - val String name; - -} 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 af18e9c0cb..f69e664ee8 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 @@ -6,6 +6,7 @@ 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.RuntimeGeneratedMappingServiceImpl; 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; @@ -42,6 +43,7 @@ public class ConnectorActivator implements Provider, ServiceTrackerCustomizer
toDataDom( - Entry, DataObject> entry) { - val key = mapping.toDataDom(entry.key); - val data = mapping.toCompositeNode(entry.value); - return new SimpleEntry(key, data); - } - - override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom( - InstanceIdentifier path) { - return mapping.toDataDom(path); - } - - override dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result) { - return mapping.dataObjectFromDataDom(path,result); - } - - public def void start() { - schemaService.registerSchemaServiceListener(this); - recreateBindingContext(schemaService.globalContext); - } -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend deleted file mode 100644 index c1efd11f24..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend +++ /dev/null @@ -1,235 +0,0 @@ -package org.opendaylight.controller.sal.binding.impl.connect.dom - -import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator -import javassist.ClassPool -import org.opendaylight.yangtools.yang.model.api.SchemaContext -import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener -import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl -import java.util.Map -import org.opendaylight.yangtools.sal.binding.model.api.Type -import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder -import org.opendaylight.yangtools.yang.model.api.SchemaNode -import java.util.HashMap -import java.util.concurrent.ConcurrentHashMap -import org.opendaylight.yangtools.yang.data.api.CompositeNode -import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import java.util.Map.Entry -import java.util.AbstractMap.SimpleEntry -import org.opendaylight.yangtools.yang.model.api.SchemaPath -import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil -import java.util.ArrayList -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode -import org.opendaylight.yangtools.binding.generator.util.Types -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates -import org.opendaylight.yangtools.yang.common.QName -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier -import org.opendaylight.yangtools.yang.binding.DataContainer -import static com.google.common.base.Preconditions.*; -import java.util.List -import org.opendaylight.yangtools.yang.data.api.Node -import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl -import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl -import org.opendaylight.yangtools.concepts.Delegator -import java.util.concurrent.ConcurrentMap -import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType -import org.opendaylight.yangtools.yang.binding.BindingCodec - -class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener { - - ClassPool pool; - - @Property - extension TransformerGenerator binding; - - val ConcurrentMap 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 87f31ac5c4..6478a03bbc 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 @@ -3,6 +3,7 @@ package org.opendaylight.controller.sal.binding.impl.util; import java.util.concurrent.Callable; +import java.util.concurrent.locks.Lock; import static com.google.common.base.Preconditions.*; @@ -10,20 +11,35 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import com.google.common.base.Optional; + public class ClassLoaderUtils { public static V withClassLoader(ClassLoader cls,Callable function) throws Exception { - checkNotNull(cls); - checkNotNull(function); + return withClassLoaderAndLock(cls, Optional.absent(), function); + } + + public static V withClassLoaderAndLock(ClassLoader cls,Lock lock,Callable function) throws Exception { + checkNotNull(lock,"Lock should not be null"); + return withClassLoaderAndLock(cls, Optional.of(lock), function); + } + + public static V withClassLoaderAndLock(ClassLoader cls,Optional lock,Callable function) throws Exception { + checkNotNull(cls, "Classloader should not be null"); + checkNotNull(function,"Function should not be null"); + if(lock.isPresent()) { + lock.get().lock(); + } ClassLoader oldCls = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(cls); V result = function.call(); - Thread.currentThread().setContextClassLoader(oldCls); return result; - } catch (Exception e) { + } finally { Thread.currentThread().setContextClassLoader(oldCls); - throw new Exception(e); + if(lock.isPresent()) { + lock.get().unlock(); + } } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java index 27d985b2d2..7d8a8f1fff 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java @@ -6,13 +6,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; +import javassist.ClassPool; + import org.junit.Before; 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.RuntimeGeneratedMappingServiceImpl; -import org.opendaylight.controller.sal.binding.test.connect.dom.MappingServiceTest; +import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; import org.opendaylight.controller.sal.core.api.data.DataBrokerService; import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; import org.opendaylight.yangtools.yang.model.api.Module; @@ -29,6 +30,12 @@ public abstract class AbstractDataServiceTest { protected DataBrokerService biDataService; protected DataProviderService baDataService; + /** + * Workaround for JUNIT sharing classloaders + * + */ + protected static final ClassPool POOL = new ClassPool(); + protected RuntimeGeneratedMappingServiceImpl mappingServiceImpl; protected BindingIndependentMappingService mappingService; protected DataBrokerImpl baDataImpl; @@ -56,6 +63,7 @@ public abstract class AbstractDataServiceTest { biDataImpl.registerCommitHandler(treeRoot, dataStore); mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl(); + mappingServiceImpl.setPool(POOL); mappingService = mappingServiceImpl; File pathname = new File("target/gen-classes-debug"); //System.out.println("Generated classes are captured in " + pathname.getAbsolutePath()); @@ -69,15 +77,17 @@ public abstract class AbstractDataServiceTest { connectorServiceImpl.start(); String[] yangFiles= getModelFilenames(); - mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles)); + if(yangFiles != null && yangFiles.length > 0) { + mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles)); + } } protected String[] getModelFilenames() { - return getModelFilenamesImpl(); + return getAllModelFilenames(); } - public static String[] getModelFilenamesImpl() { + public static String[] getAllModelFilenames() { Predicate predicate = new Predicate() { @Override public boolean apply(String input) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java index 08eb409b3d..4e7628fd06 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java @@ -1,22 +1,41 @@ package org.opendaylight.controller.sal.binding.test.bugfix; +import java.util.ArrayList; +import java.util.Arrays; 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 java.util.concurrent.Future; 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.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.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.config.rev130819.Flows; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions; +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.Match; 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.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.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.NodesBuilder; 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; @@ -27,78 +46,130 @@ 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.FluentIterable; import com.google.common.collect.ImmutableMap; +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.*; -/** - * - * Testcase for https://bugs.opendaylight.org/show_bug.cgi?id=144 - * - * Cannot compile CoDec for org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow - * - * @author ttkacik - * - */ public class DOMCodecBug01Test 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 String NODE_ID = "node:1"; private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); - private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder().node(Nodes.class) - .node(Node.class, NODE_KEY).toInstance(); - - + private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, NODE_ID); - + + private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder() // + .node(Nodes.class) // + .toInstance(); + + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = // + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // + .node(Nodes.QNAME) // + .toInstance(); + + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() // + .node(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(); + 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 FlowKey FLOW_KEY = new FlowKey(FLOW_ID, NODE_REF); private static final Map FLOW_KEY_BI = // - ImmutableMap.of(FLOW_ID_QNAME, FLOW_ID, FLOW_NODE_QNAME, NODE_REF); - - - + ImmutableMap. of(FLOW_ID_QNAME, FLOW_ID, FLOW_NODE_QNAME, NODE_INSTANCE_ID_BI); 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(); + 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(Flows.class) // - .node(Flow.class, FLOW_KEY) // - .toInstance(); + InstanceIdentifier.builder() // + .node(Flows.class) // + .node(Flow.class, FLOW_KEY) // + .toInstance(); + + + /** - * + * + * Testcase for https://bugs.opendaylight.org/show_bug.cgi?id= + * + * Cannot compile CoDec for + * org.opendaylight.yang.gen.v1.urn.opendaylight.flow + * .config.rev130819.flows.Flow + * * When invoking following code in the consumer, user got an * IllegalStateException during creation of mapping between Java DTOs and * data-dom. - * + * * Exception was compilation error which was caused by incorect generation * of code. - * - * + * + * Reported by Depthi V V + * */ @Test public void testIndirectGeneration() throws Exception { + ExecutorService basePool = Executors.newFixedThreadPool(2); + ListeningExecutorService listenablePool = MoreExecutors.listeningDecorator(basePool); + + createFlow(); + + Object lock = new Object(); + CreateFlowTask task1 = new CreateFlowTask(lock); + CreateFlowTask task2 = new CreateFlowTask(lock); + CreateFlowTask task3 = new CreateFlowTask(lock); + + ListenableFuture task1Future = listenablePool.submit(task1); + ListenableFuture task2Future = listenablePool.submit(task2); + ListenableFuture task3Future = listenablePool.submit(task3); + + + ListenableFuture> compositeFuture = Futures.allAsList(task1Future,task2Future,task3Future); + + Thread.sleep(500); + //lock.notifyAll(); + compositeFuture.get(); + + verifyDataAreStoredProperly(); + + DataModificationTransaction modification2 = baDataService.beginTransaction(); + modification2.removeConfigurationData(FLOW_INSTANCE_ID_BA); + + DataObject originalData = modification2.getOriginalConfigurationData().get(FLOW_INSTANCE_ID_BA); + assertNotNull(originalData); + RpcResult ret2 = modification2.commit().get(); + + assertNotNull(ret2); + assertEquals(TransactionStatus.COMMITED, ret2.getResult()); + + // Data are not in the store. + assertNull(baDataService.readOperationalData(FLOW_INSTANCE_ID_BA)); + + } + + private void createFlow() throws Exception { + DataModificationTransaction modification = baDataService.beginTransaction(); - FlowBuilder flow = new FlowBuilder(); + FlowBuilder flow = new FlowBuilder(); MatchBuilder match = new MatchBuilder(); VlanMatchBuilder vlanBuilder = new VlanMatchBuilder(); VlanIdBuilder vlanIdBuilder = new VlanIdBuilder(); @@ -110,35 +181,58 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { flow.setMatch(match.build()); flow.setNode(NODE_REF); + + InstructionsBuilder instructions = new InstructionsBuilder(); + InstructionBuilder instruction = new InstructionBuilder(); + ApplyActionsBuilder applyActions = new ApplyActionsBuilder(); + List actionList = new ArrayList<>(); + PopMplsActionBuilder popMplsAction = new PopMplsActionBuilder(); + popMplsAction.setEthernetType(34); + actionList.add(new ActionBuilder().setAction(popMplsAction.build()).build()); + + applyActions.setAction(actionList ); + + + instruction.setInstruction(applyActions.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()); - - verifyDataAreStoredProperly(); - - - DataModificationTransaction modification2 = baDataService.beginTransaction(); - modification2.removeConfigurationData(FLOW_INSTANCE_ID_BA); - - DataObject originalData = modification2.getOriginalConfigurationData().get(FLOW_INSTANCE_ID_BA); - assertNotNull(originalData); - RpcResult ret2 = modification2.commit().get(); - - assertNotNull(ret2); - assertEquals(TransactionStatus.COMMITED, ret2.getResult()); - - - // Data are not in the store. - assertNull(baDataService.readOperationalData(FLOW_INSTANCE_ID_BA)); - - + } + + private class CreateFlowTask implements Callable { + + final Object startSyncObject; + + public CreateFlowTask(Object startSync) { + startSyncObject = startSync; + } + + @Override + public Void call() { + try { + //startSyncObject.wait(); + //Thread.sleep(500); + createFlow(); + } catch (Exception e) { + throw new RuntimeException(e); + } + return null; + } } private void verifyDataAreStoredProperly() { CompositeNode biFlow = biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI); assertNotNull(biFlow); - CompositeNode biMatch = biFlow.getFirstCompositeByName(QName.create(Flow.QNAME,Match.QNAME.getLocalName())); + CompositeNode biMatch = biFlow.getFirstCompositeByName(QName.create(Flow.QNAME, Match.QNAME.getLocalName())); assertNotNull(biMatch); } + + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java new file mode 100644 index 0000000000..773bab80f1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java @@ -0,0 +1,121 @@ +package org.opendaylight.controller.sal.binding.test.bugfix; + +import java.util.Arrays; +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 java.util.concurrent.Future; + +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.flow.config.rev130819.Flows; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +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.NodesBuilder; +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.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.FluentIterable; +import com.google.common.collect.ImmutableMap; +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 DOMCodecBug02Test 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 String FLOW_ID = "foo"; + private static final String NODE_ID = "node:1"; + + private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); + + private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, + NODE_ID); + + private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder() // + .node(Nodes.class) // + .toInstance(); + + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = // + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // + .node(Nodes.QNAME) // + .toInstance(); + + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() // + .node(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); + + @Override + protected String[] getModelFilenames() { + return null; + } + + /** + * + * + * @throws Exception + */ + @Test + public void testSchemaContextNotAvailable() throws Exception { + + ExecutorService testExecutor = Executors.newFixedThreadPool(1); + + Future>> future = testExecutor.submit(new Callable>>() { + @Override + public Future> call() throws Exception { + NodesBuilder nodesBuilder = new NodesBuilder(); + nodesBuilder.setNode(Collections. emptyList()); + DataModificationTransaction transaction = baDataService.beginTransaction(); + transaction.putOperationalData(NODES_INSTANCE_ID_BA, nodesBuilder.build()); + return transaction.commit(); + } + }); + mappingServiceImpl.onGlobalContextUpdated(getContext(getAllModelFilenames())); + + RpcResult result = future.get().get(); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + + + Nodes nodes = checkForNodes(); + assertNotNull(nodes); + + } + + private Nodes checkForNodes() { + return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA); + + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java new file mode 100644 index 0000000000..ae54591a23 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java @@ -0,0 +1,156 @@ +package org.opendaylight.controller.sal.binding.test.bugfix; + +import java.util.Arrays; +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 java.util.concurrent.Future; + +import org.junit.Test; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; +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.NodesBuilder; +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.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.FluentIterable; +import com.google.common.collect.ImmutableMap; +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 DOMCodecBug03Test extends AbstractDataServiceTest implements DataChangeListener { + + private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); + private static final String NODE_ID = "openflow:1"; + + private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); + + private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, + NODE_ID); + + private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder() // + .node(Nodes.class) // + .toInstance(); + + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = // + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // + .node(Nodes.QNAME) // + .toInstance(); + + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() // + .node(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 DataChangeEvent, DataObject> receivedChangeEvent; + + + + /** + * Test for Bug 148 + * + * @throws Exception + */ + @Test + public void testAugmentSerialization() throws Exception { + + + baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this); + + NodeBuilder nodeBuilder = new NodeBuilder(); + nodeBuilder.setId(new NodeId(NODE_ID)); + nodeBuilder.setKey(NODE_KEY); + DataModificationTransaction transaction = baDataService.beginTransaction(); + + + FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder(); + fnub.setHardware("Hardware Foo"); + fnub.setManufacturer("Manufacturer Foo"); + fnub.setSerialNumber("Serial Foo"); + fnub.setDescription("Description Foo"); + fnub.setSoftware("JUnit emulated"); + FlowCapableNode fnu = fnub.build(); + nodeBuilder.addAugmentation(FlowCapableNode.class, fnu); + Node original = nodeBuilder.build(); + transaction.putOperationalData(NODE_INSTANCE_ID_BA, original); + + RpcResult result = transaction.commit().get(); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + + assertNotNull(receivedChangeEvent); + + verifyNodes((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(),original); + assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); + Nodes nodes = checkForNodes(); + verifyNodes(nodes,original); + + + } + + private void verifyNodes(Nodes nodes,Node original) { + assertNotNull(nodes); + assertNotNull(nodes.getNode()); + assertEquals(1, nodes.getNode().size()); + Node readedNode = nodes.getNode().get(0); + assertEquals(original.getId(), readedNode.getId()); + assertEquals(original.getKey(), readedNode.getKey()); + + FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class); + FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class); + assertNotNull(fnu); + assertEquals(fnu.getDescription(), readedAugment.getDescription()); + assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber()); + + } + + private void assertBindingIndependentVersion( + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) { + CompositeNode node = biDataService.readOperationalData(nodeId); + assertNotNull(node); + } + + private Nodes checkForNodes() { + return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA); + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + receivedChangeEvent = change; + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java deleted file mode 100644 index e26273e026..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.opendaylight.controller.sal.binding.test.connect.dom; - -import static org.junit.Assert.*; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.junit.Before; -import org.junit.Test; -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.test.AbstractDataServiceTest; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; -import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; - -public class MappingServiceTest { - - private static final QName NODES = QName.create("urn:opendaylight:inventory", "2013-08-19", "nodes"); - private static final QName NODE = QName.create(NODES,"node"); - private static final QName ID = QName.create(NODES,"id"); - - BindingIndependentMappingService service; - private MappingServiceImpl impl; - - @Before - public void setUp() { - impl = new MappingServiceImpl(); - service = impl; - } - - @Test - public void baDataToBiData() throws Exception { - - String[] yangFiles = AbstractDataServiceTest.getModelFilenamesImpl(); - - SchemaContext ctx = AbstractDataServiceTest.getContext(yangFiles); - - impl.onGlobalContextUpdated(ctx); - - NodesBuilder nodes = new NodesBuilder(); - - List nodeList = new ArrayList<>(); - nodeList.add(createChildNode("foo")); - nodeList.add(createChildNode("bar")); - - nodes.setNode(nodeList); - Nodes nodesTO = nodes.build(); - CompositeNode xmlNodes = service.toDataDom(nodesTO); - assertNotNull(xmlNodes); - List invNodes = xmlNodes.getCompositesByName(NODE); - assertNotNull(invNodes); - assertEquals(2, invNodes.size()); - } - - @Test - public void instanceIdentifierTest() throws Exception { - - String[] yangFiles = AbstractDataServiceTest.getModelFilenamesImpl(); - SchemaContext ctx = AbstractDataServiceTest.getContext(yangFiles); - impl.onGlobalContextUpdated(ctx); - - NodeKey nodeKey = new NodeKey(new NodeId("foo")); - InstanceIdentifier path = InstanceIdentifier.builder().node(Nodes.class).child(Node.class, nodeKey).toInstance(); - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier result = service.toDataDom(path); - assertNotNull(result); - assertEquals(2, result.getPath().size()); - } - - private Node createChildNode(String id) { - NodeBuilder node = new NodeBuilder(); - NodeId nodeId = new NodeId(id); - - node.setId(nodeId); - node.setKey(new NodeKey(nodeId)); - - FlowCapableNodeBuilder aug = new FlowCapableNodeBuilder(); - aug.setManufacturer(id); - node.addAugmentation(FlowCapableNode.class, aug.build()); - - return node.build(); - } - -} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend index b878071183..74c4e0a148 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend @@ -27,25 +27,37 @@ import java.util.concurrent.Future import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter import org.opendaylight.yangtools.concepts.Path import org.slf4j.LoggerFactory - -abstract class AbstractDataBroker

,D,DCL extends DataChangeListener> implements -DataModificationTransactionFactory, // +import java.util.HashSet +import java.util.Map.Entry +import java.util.Iterator +import java.util.Collection +import com.google.common.collect.FluentIterable; +import java.util.Set +import com.google.common.collect.ImmutableList + +abstract class AbstractDataBroker

, D, DCL extends DataChangeListener> implements DataModificationTransactionFactory, // DataReader, // DataChangePublisher, // -DataProvisionService { +DataProvisionService { @Property var ExecutorService executor; @Property - var AbstractDataReadRouter dataReadRouter; - - Multimap> listeners = HashMultimap.create(); - Multimap> commitHandlers = HashMultimap.create(); + var AbstractDataReadRouter dataReadRouter; + Multimap> listeners = HashMultimap.create(); + Multimap> commitHandlers = HashMultimap.create(); public new() { - + } + + protected def /*Iterator>,D>>*/ affectedCommitHandlers( + HashSet

paths) { + return FluentIterable.from(commitHandlers.asMap.entrySet) + .filter[key.isAffectedBy(paths)] // + .transformAndConcat [value] // + .transform[instance].toList() } override final readConfigurationData(P path) { @@ -56,11 +68,10 @@ DataProvisionService { return dataReadRouter.readOperationalData(path); } - override final registerCommitHandler(P path, - DataCommitHandler commitHandler) { - val registration = new DataCommitHandlerRegistration(path,commitHandler,this); - commitHandlers.put(path,registration) - return registration; + override final registerCommitHandler(P path, DataCommitHandler commitHandler) { + val registration = new DataCommitHandlerRegistration(path, commitHandler, this); + commitHandlers.put(path, registration) + return registration; } override final def registerDataChangeListener(P path, DCL listener) { @@ -69,27 +80,49 @@ DataProvisionService { return reg; } - final def registerDataReader(P path,DataReader reader) { - - val confReg = dataReadRouter.registerConfigurationReader(path,reader); - val dataReg = dataReadRouter.registerOperationalReader(path,reader); - - return new CompositeObjectRegistration(reader,Arrays.asList(confReg,dataReg)); + final def registerDataReader(P path, DataReader reader) { + + val confReg = dataReadRouter.registerConfigurationReader(path, reader); + val dataReg = dataReadRouter.registerOperationalReader(path, reader); + + return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg)); } - protected final def removeListener(DataChangeListenerRegistration registration) { + protected final def removeListener(DataChangeListenerRegistration registration) { listeners.remove(registration.path, registration); } - protected final def removeCommitHandler(DataCommitHandlerRegistration registration) { + protected final def removeCommitHandler(DataCommitHandlerRegistration registration) { commitHandlers.remove(registration.path, registration); } - - protected final def getActiveCommitHandlers() { - return commitHandlers.entries.map[ value.instance].toSet + + protected final def getActiveCommitHandlers() { + return commitHandlers.entries; } - package final def Future> commit(AbstractDataTransaction transaction) { + protected def /*Iterator>,D>>*/ affectedListenersWithInitialState( + HashSet

paths) { + return FluentIterable.from(listeners.asMap.entrySet).filter[key.isAffectedBy(paths)].transform [ + val operationalState = readOperationalData(key) + val configurationState = readConfigurationData(key) + return new ListenerStateCapture(key, value, operationalState, configurationState) + ].toList() + } + + protected def boolean isAffectedBy(P key, Set

paths) { + if (paths.contains(key)) { + return true; + } + for (path : paths) { + if (key.contains(path)) { + return true; + } + } + + return false; + } + + package final def Future> commit(AbstractDataTransaction transaction) { checkNotNull(transaction); transaction.changeStatus(TransactionStatus.SUBMITED); val task = new TwoPhaseCommit(transaction, this); @@ -98,14 +131,30 @@ DataProvisionService { } -package class DataChangeListenerRegistration

,D,DCL extends DataChangeListener> extends AbstractObjectRegistration implements ListenerRegistration { +@Data +package class ListenerStateCapture

, D,DCL extends DataChangeListener> { - AbstractDataBroker dataBroker; + @Property + P path; + + @Property + Collection> listeners; + + @Property + D initialOperationalState; + + @Property + D initialConfigurationState; +} + +package class DataChangeListenerRegistration

, D, DCL extends DataChangeListener> extends AbstractObjectRegistration implements ListenerRegistration { + + AbstractDataBroker dataBroker; @Property val P path; - new(P path, DCL instance, AbstractDataBroker broker) { + new(P path, DCL instance, AbstractDataBroker broker) { super(instance) dataBroker = broker; _path = path; @@ -118,16 +167,14 @@ package class DataChangeListenerRegistration

,D,DCL extends Dat } -package class DataCommitHandlerRegistration

,D> -extends AbstractObjectRegistration> { +package class DataCommitHandlerRegistration

, D> extends AbstractObjectRegistration> { - AbstractDataBroker dataBroker; + AbstractDataBroker dataBroker; @Property val P path; - new(P path, DataCommitHandler instance, - AbstractDataBroker broker) { + new(P path, DataCommitHandler instance, AbstractDataBroker broker) { super(instance) dataBroker = broker; _path = path; @@ -140,74 +187,105 @@ extends AbstractObjectRegistration> { } -package class TwoPhaseCommit

,D> implements Callable> { - +package class TwoPhaseCommit

, D,DCL extends DataChangeListener> implements Callable> { + private static val log = LoggerFactory.getLogger(TwoPhaseCommit); - val AbstractDataTransaction transaction; - val AbstractDataBroker dataBroker; + val AbstractDataTransaction transaction; + val AbstractDataBroker dataBroker; - new(AbstractDataTransaction transaction, AbstractDataBroker broker) { + new(AbstractDataTransaction transaction, AbstractDataBroker broker) { this.transaction = transaction; this.dataBroker = broker; } override call() throws Exception { - val Iterable> commitHandlers = dataBroker.activeCommitHandlers; + // get affected paths + val affectedPaths = new HashSet

(); + + affectedPaths.addAll(transaction.createdConfigurationData.keySet); + affectedPaths.addAll(transaction.updatedConfigurationData.keySet); + affectedPaths.addAll(transaction.removedConfigurationData); + + affectedPaths.addAll(transaction.createdOperationalData.keySet); + affectedPaths.addAll(transaction.updatedOperationalData.keySet); + affectedPaths.addAll(transaction.removedOperationalData); + + val listeners = dataBroker.affectedListenersWithInitialState(affectedPaths); // requesting commits + val Iterable> commitHandlers = dataBroker.affectedCommitHandlers(affectedPaths); val List> handlerTransactions = new ArrayList(); try { for (handler : commitHandlers) { handlerTransactions.add(handler.requestCommit(transaction)); } } catch (Exception e) { - log.error("Request Commit failded",e); - return rollback(handlerTransactions,e); + log.error("Request Commit failded", e); + return rollback(handlerTransactions, e); } val List> results = new ArrayList(); try { for (subtransaction : handlerTransactions) { results.add(subtransaction.finish()); } + listeners.publishDataChangeEvent(); } catch (Exception e) { - log.error("Finish Commit failed",e); - return rollback(handlerTransactions,e); + log.error("Finish Commit failed", e); + return rollback(handlerTransactions, e); } + return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet()); + + } + + def void publishDataChangeEvent(ImmutableList> listeners) { + for(listenerSet : listeners) { + val updatedConfiguration = dataBroker.readConfigurationData(listenerSet.path); + val updatedOperational = dataBroker.readOperationalData(listenerSet.path); + + val changeEvent = new DataChangeEventImpl(transaction,listenerSet.initialConfigurationState,listenerSet.initialOperationalState,updatedOperational,updatedConfiguration); + for(listener : listenerSet.listeners) { + try { + listener.instance.onDataChanged(changeEvent); + + } catch (Exception e) { + e.printStackTrace(); + } + } + } } - def rollback(List> transactions,Exception e) { + def rollback(List> transactions, Exception e) { for (transaction : transactions) { transaction.rollback() } + // FIXME return encountered error. return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet()); } } - public abstract class AbstractDataTransaction

, D> extends AbstractDataModification { @Property private val Object identifier; - var TransactionStatus status; - - + var AbstractDataBroker broker; - protected new (AbstractDataBroker dataBroker) { + protected new(AbstractDataBroker dataBroker) { super(dataBroker); _identifier = new Object(); broker = dataBroker; status = TransactionStatus.NEW; - //listeners = new ListenerRegistry<>(); + + //listeners = new ListenerRegistry<>(); } - override commit() { + override commit() { return broker.commit(this); } @@ -230,7 +308,7 @@ public abstract class AbstractDataTransaction

, D> extends Abst return false; if (getClass() != obj.getClass()) return false; - val other = (obj as AbstractDataTransaction) ; + val other = (obj as AbstractDataTransaction); if (broker == null) { if (other.broker != null) return false; @@ -248,12 +326,11 @@ public abstract class AbstractDataTransaction

, D> extends Abst return status; } - protected abstract def void onStatusChange(TransactionStatus status); - + public def changeStatus(TransactionStatus status) { this.status = status; onStatusChange(status); } - + } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java new file mode 100644 index 0000000000..4eb9586fdf --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java @@ -0,0 +1,73 @@ +package org.opendaylight.controller.md.sal.common.impl.service; + +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.data.DataChange; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; + +public class DataChangeEventImpl implements DataChangeEvent { + + private final DataChange dataChange; + + private final D originalConfigurationSubtree; + private final D originalOperationalSubtree; + private final D updatedOperationalSubtree; + private final D updatedConfigurationSubtree; + + + + + public DataChangeEventImpl(DataChange dataChange, D originalConfigurationSubtree, + D originalOperationalSubtree, D updatedOperationalSubtree, D updatedConfigurationSubtree) { + super(); + this.dataChange = dataChange; + this.originalConfigurationSubtree = originalConfigurationSubtree; + this.originalOperationalSubtree = originalOperationalSubtree; + this.updatedOperationalSubtree = updatedOperationalSubtree; + this.updatedConfigurationSubtree = updatedConfigurationSubtree; + } + + @Override + public D getUpdatedOperationalSubtree() { + return updatedOperationalSubtree; + } + + @Override + public D getUpdatedConfigurationSubtree() { + return updatedConfigurationSubtree; + } + + public Map getCreatedOperationalData() { + return dataChange.getCreatedOperationalData(); + } + + public Map getCreatedConfigurationData() { + return dataChange.getCreatedConfigurationData(); + } + + public Map getUpdatedOperationalData() { + return dataChange.getUpdatedOperationalData(); + } + + public Map getUpdatedConfigurationData() { + return dataChange.getUpdatedConfigurationData(); + } + + public Set

getRemovedConfigurationData() { + return dataChange.getRemovedConfigurationData(); + } + + public Set

getRemovedOperationalData() { + return dataChange.getRemovedOperationalData(); + } + + public Map getOriginalConfigurationData() { + return dataChange.getOriginalConfigurationData(); + } + + public Map getOriginalOperationalData() { + return dataChange.getOriginalOperationalData(); + } + +}