From cd291bddce7a6e647d8c5193b45cd6573b23139f Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Thu, 23 Jan 2014 10:01:05 +0100 Subject: [PATCH] Move RuntimeGeneratedMappingService from md-sal to yang-data-impl(codecs + apis) and binding-generator-impl(service implementation) Signed-off-by: Maros Marsalek Change-Id: I44b19aa5221baf8e954553789e96f0cb662703d9 --- code-generator/binding-generator-impl/pom.xml | 8 + .../generator/impl/BindingClassListener.java | 8 + .../binding/generator/impl/CodecMapping.java | 105 ++ .../generator/impl/CodecTypeUtils.java | 15 + .../generator/impl/GeneratorListener.java | 22 + .../impl/InstanceIdentifierCodecImpl.xtend | 151 ++ .../generator/impl/IntermediateMapping.xtend | 48 + .../impl/LazyGeneratedCodecRegistry.java | 976 ++++++++++ .../RuntimeGeneratedMappingServiceImpl.xtend | 302 ++++ .../impl/StaticFieldInitializer.java | 6 + .../generator/impl/TransformerGenerator.xtend | 1566 +++++++++++++++++ .../generator/util/ClassGenerator.java | 7 + .../generator/util/ClassLoaderUtils.java | 85 + .../util/CodeGenerationException.java | 25 + .../generator/util/FieldGenerator.java | 7 + .../generator/util/JavassistUtils.xtend | 128 ++ .../generator/util/MethodGenerator.java | 7 + .../binding/generator/util/XtendHelper.java | 14 + .../generator/util/YangSchemaUtils.java | 63 + code-generator/pom.xml | 15 +- pom.xml | 3 +- yang/yang-data-impl/pom.xml | 4 + .../data/impl/codec/AugmentationCodec.java | 18 + .../BindingIndependentMappingService.java | 32 + .../yang/data/impl/codec/ChoiceCaseCodec.java | 16 + .../yang/data/impl/codec/ChoiceCodec.java | 12 + .../yang/data/impl/codec/CodecRegistry.java | 39 + .../data/impl/codec/DataContainerCodec.java | 15 + .../impl/codec/DeserializationException.java | 24 + .../yang/data/impl/codec/DomCodec.java | 16 + .../yang/data/impl/codec/IdentifierCodec.java | 14 + .../yang/data/impl/codec/IdentitityCodec.java | 14 + .../impl/codec/InstanceIdentifierCodec.java | 13 + .../yang/data/impl/codec/ValueWithQName.java | 72 + .../yang/model/api/SchemaServiceListener.java | 12 + 35 files changed, 3859 insertions(+), 3 deletions(-) create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingClassListener.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecMapping.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecTypeUtils.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratorListener.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.xtend create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/IntermediateMapping.xtend create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.xtend create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/StaticFieldInitializer.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassGenerator.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/CodeGenerationException.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/FieldGenerator.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.xtend create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/MethodGenerator.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/XtendHelper.java create mode 100644 code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/YangSchemaUtils.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/AugmentationCodec.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/BindingIndependentMappingService.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCaseCodec.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCodec.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/CodecRegistry.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DataContainerCodec.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DeserializationException.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DomCodec.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentifierCodec.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentitityCodec.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/InstanceIdentifierCodec.java create mode 100644 yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ValueWithQName.java create mode 100644 yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaServiceListener.java diff --git a/code-generator/binding-generator-impl/pom.xml b/code-generator/binding-generator-impl/pom.xml index 29410091ff..f46d14e22c 100644 --- a/code-generator/binding-generator-impl/pom.xml +++ b/code-generator/binding-generator-impl/pom.xml @@ -10,6 +10,10 @@ binding-generator-impl + + org.javassist + javassist + org.opendaylight.yangtools binding-generator-util @@ -18,6 +22,10 @@ org.opendaylight.yangtools yang-parser-impl + + org.opendaylight.yangtools + yang-data-impl + org.opendaylight.yangtools binding-generator-api diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingClassListener.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingClassListener.java new file mode 100644 index 0000000000..fd7589df69 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingClassListener.java @@ -0,0 +1,8 @@ +package org.opendaylight.yangtools.sal.binding.generator.impl; + +public interface BindingClassListener { + + void onBindingClassCaptured(Class cls); + + void onBindingClassProcessed(Class cls); +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecMapping.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecMapping.java new file mode 100644 index 0000000000..caf0216ee9 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecMapping.java @@ -0,0 +1,105 @@ +package org.opendaylight.yangtools.sal.binding.generator.impl; + +import java.lang.reflect.Field; +import java.util.Map; + +import org.opendaylight.yangtools.yang.data.impl.codec.IdentitityCodec; +import org.opendaylight.yangtools.yang.data.impl.codec.InstanceIdentifierCodec; +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CodecMapping { + + private static final Logger LOG = LoggerFactory.getLogger(CodecMapping.class); + + public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_CODEC"; + public static final String IDENTITYREF_CODEC = "IDENTITYREF_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); + if(obj != null) { + instanceIdField.set(null, codec); + } + } catch (NoSuchFieldException e) { + LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e); + } catch (SecurityException | IllegalAccessException e) { + LOG.error("Instance identifier could not be set for {}",obj.getName(),e); + } + } + + + public static void setIdentityRefCodec(Class obj,IdentitityCodec codec) { + Field instanceIdField; + try { + instanceIdField = obj.getField(IDENTITYREF_CODEC); + if(obj != null) { + instanceIdField.set(null, codec); + } + } catch (NoSuchFieldException e) { + LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e); + } catch (SecurityException | IllegalAccessException e) { + LOG.error("Instance identifier could not be set for {}",obj.getName(),e); + } + } + + public static void setClassToCaseMap(Class> codec, + Map,BindingCodec> classToCaseRawCodec) { + Field instanceIdField; + try { + instanceIdField = codec.getField(CLASS_TO_CASE_MAP); + instanceIdField.set(null, classToCaseRawCodec); + } catch (NoSuchFieldException e) { + LOG.debug("BUG: Class to case mappping is not needed for {}",codec.getName(),e); + } catch (SecurityException | IllegalAccessException e) { + LOG.error("Class to case mappping could not be set for {}",codec.getName(),e); + } + } + + public static void setCompositeNodeToCaseMap(Class> codec, + Map> compositeToCase) { + Field instanceIdField; + try { + instanceIdField = codec.getField(COMPOSITE_TO_CASE); + instanceIdField.set(null, compositeToCase); + } catch (NoSuchFieldException e) { + LOG.debug("BUG: Class to case mappping is not needed for {}",codec.getName(),e); + } catch (SecurityException | IllegalAccessException e) { + LOG.error("Composite node to case mappping could not be set for {}",codec.getName(),e); + } + } + + public static void setAugmentationCodec(Class> dataCodec, + BindingCodec augmentableCodec) { + Field instanceIdField; + try { + instanceIdField = dataCodec.getField(AUGMENTATION_CODEC); + instanceIdField.set(null, augmentableCodec); + } catch (NoSuchFieldException e) { + LOG.debug("BUG: Augmentation codec is not needed for {}",dataCodec.getName(),e); + } catch (SecurityException | IllegalAccessException e) { + LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e); + } + } + + + public static BindingCodec getAugmentationCodec(Class> dataCodec) { + Field instanceIdField; + try { + instanceIdField = dataCodec.getField(AUGMENTATION_CODEC); + return (BindingCodec) instanceIdField.get(null); + } catch (NoSuchFieldException e) { + LOG.debug("BUG: Augmentation codec is not needed for {}",dataCodec.getName(),e); + } catch (SecurityException | IllegalAccessException e) { + LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e); + } + return null; + } +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecTypeUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecTypeUtils.java new file mode 100644 index 0000000000..1cba8de909 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/CodecTypeUtils.java @@ -0,0 +1,15 @@ +package org.opendaylight.yangtools.sal.binding.generator.impl; + +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; + +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/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratorListener.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratorListener.java new file mode 100644 index 0000000000..91fca368fd --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratorListener.java @@ -0,0 +1,22 @@ +package org.opendaylight.yangtools.sal.binding.generator.impl; + +import java.util.Map; + +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.ChoiceNode; + +public interface GeneratorListener { + + + + void onClassProcessed(Class cl); + + void onCodecCreated(Class codec); + void onValueCodecCreated(Class valueClass, Class valueCodec); + void onCaseCodecCreated(Class choiceClass, Class, Object>> choiceCodec); + void onDataContainerCodecCreated(Class dataClass, Class> dataCodec); + + void onChoiceCodecCreated(Class choiceClass, + Class, Object>> choiceCodec, ChoiceNode schema); +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.xtend new file mode 100644 index 0000000000..42fb8d984c --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/InstanceIdentifierCodecImpl.xtend @@ -0,0 +1,151 @@ +package org.opendaylight.yangtools.sal.binding.generator.impl + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yangtools.yang.data.impl.codec.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.yangtools.yang.data.impl.codec.InstanceIdentifierCodec +import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName +import java.util.HashMap +import org.slf4j.LoggerFactory +import java.util.List +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.yangtools.yang.data.impl.codec.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 +import org.opendaylight.yangtools.yang.binding.Augmentable +import com.google.common.collect.ImmutableList +import org.opendaylight.yangtools.yang.binding.Augmentation +import java.util.concurrent.ConcurrentHashMap +import org.opendaylight.yangtools.yang.binding.util.BindingReflections + +class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { + + private static val LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl); + val CodecRegistry codecRegistry; + + val Map, Map, Class>> classToPreviousAugment = 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) + baType = baArg?.type + val injectAugment = classToPreviousAugment.get(baType); + if(injectAugment != null) { + val augment = injectAugment.get(scannedPath) as Class; + if(augment != null) { + baArgs.add(new Item(augment)); + } + } + baArgs.add(baArg) + } + val ret = new InstanceIdentifier(baArgs,baType as Class); + LOG.debug("DOM Instance Identifier {} deserialized to {}",input,ret); + 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) { + var Class previousAugmentation = null + val pathArgs = input.path as List + var QName previousQName = null; + val components = new ArrayList(pathArgs.size); + val qnamePath = new ArrayList(pathArgs.size); + for(baArg : pathArgs) { + + if(!Augmentation.isAssignableFrom(baArg.type)) { + + val biArg = serializePathArgument(baArg,previousQName); + previousQName = biArg.nodeType; + components.add(biArg); + qnamePath.add(biArg.nodeType); + val immutableList = ImmutableList.copyOf(qnamePath); + codecRegistry.putPathToClass(immutableList,baArg.type); + if(previousAugmentation !== null) { + updateAugmentationInjection(baArg.type,immutableList,previousAugmentation) + } + + previousAugmentation = null; + } else { + previousQName = codecRegistry.getQNameForAugmentation(baArg.type as Class); + previousAugmentation = baArg.type; + } + } + val ret = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(components); + LOG.debug("Binding Instance Identifier {} serialized to DOM InstanceIdentifier {}",input,ret); + return ret; + } + + def updateAugmentationInjection(Class class1, ImmutableList list, Class augmentation) { + if(classToPreviousAugment.get(class1) == null) { + classToPreviousAugment.put(class1,new ConcurrentHashMap()); + } + classToPreviousAugment.get(class1).put(list,augmentation); + } + + private def dispatch PathArgument serializePathArgument(Item argument, QName previousQname) { + val type = argument.type; + val qname = BindingReflections.findQName(type); + if(previousQname == null) { + return new NodeIdentifier(qname); + } + return new NodeIdentifier(QName.create(previousQname,qname.localName)); + } + + @SuppressWarnings("rawtypes") + 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 = BindingReflections.findQName(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); + } +} \ No newline at end of file diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/IntermediateMapping.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/IntermediateMapping.xtend new file mode 100644 index 0000000000..63fc325d4e --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/IntermediateMapping.xtend @@ -0,0 +1,48 @@ +package org.opendaylight.yangtools.sal.binding.generator.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) { + if(map instanceof Node) { + return map as Node; + } + 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) { + if(obj instanceof Node) { + values.add(obj as Node); + } else if(obj instanceof Map) { + 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/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java new file mode 100644 index 0000000000..fa25e95c84 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java @@ -0,0 +1,976 @@ +package org.opendaylight.yangtools.sal.binding.generator.impl; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils; +import org.opendaylight.yangtools.yang.data.impl.codec.*; +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.sal.binding.model.api.ConcreteType; +import org.opendaylight.yangtools.sal.binding.model.api.Type; +import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder; +import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder; +import org.opendaylight.yangtools.yang.binding.*; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +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.data.impl.CompositeNodeTOImpl; +import org.opendaylight.yangtools.yang.model.api.*; +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +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 final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec(); + + private TransformerGenerator generator; + + // Concrete class to codecs + private static final Map, DataContainerCodec> containerCodecs = new WeakHashMap<>(); + private static final Map, IdentifierCodec> identifierCodecs = new WeakHashMap<>(); + private static final Map, ChoiceCodecImpl> choiceCodecs = new WeakHashMap<>(); + private static final Map, ChoiceCaseCodecImpl> caseCodecs = new WeakHashMap<>(); + private static final Map, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>(); + private static final Map, AugmentationCodec> augmentationCodecs = new WeakHashMap<>(); + private static final Map, QName> identityQNames = new WeakHashMap<>(); + private static final Map qnamesToIdentityMap = new ConcurrentHashMap<>(); + /** Binding type to encountered classes mapping **/ + @SuppressWarnings("rawtypes") + private static final Map> typeToClass = new ConcurrentHashMap<>(); + + @SuppressWarnings("rawtypes") + private static final ConcurrentMap typeToCaseCodecs = new ConcurrentHashMap<>(); + + private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade(); + + private static final Map pathToType = new ConcurrentHashMap<>(); + private static final Map, Type> pathToInstantiatedType = new ConcurrentHashMap<>(); + private static final Map typeToQname = 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) { + AugmentationCodec codec = null; + @SuppressWarnings("rawtypes") + AugmentationCodec potentialCodec = augmentationCodecs.get(object); + if (potentialCodec != null) { + codec = potentialCodec; + } else + try { + Class, Object>> augmentRawCodec = generator + .augmentationTransformerFor(object); + BindingCodec, Object> rawCodec = augmentRawCodec.newInstance(); + codec = new AugmentationCodecWrapper(rawCodec); + augmentationCodecs.put(augmentRawCodec, codec); + } catch (InstantiationException e) { + LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e); + } catch (IllegalAccessException e) { + LOG.debug("BUG: Constructor for {} is not accessible.", object.getSimpleName(), e); + } + Class> objectSupertype = getAugmentableArgumentFrom(object); + if (objectSupertype != null) { + getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec); + } else { + LOG.warn("Could not find augmentation target for augmentation {}", object); + } + return codec; + } + + @Override + public QName getQNameForAugmentation(Class cls) { + Preconditions.checkArgument(Augmentation.class.isAssignableFrom(cls)); + return getCodecForAugmentation((Class)cls).getAugmentationQName(); + } + + private static Class> getAugmentableArgumentFrom( + final Class> augmentation) { + try { + Class> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(), + new Callable>>() { + @Override + @SuppressWarnings("unchecked") + public Class> call() throws Exception { + for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) { + if (supertype instanceof ParameterizedType + && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) { + ParameterizedType augmentationGeneric = (ParameterizedType) supertype; + return (Class>) augmentationGeneric + .getActualTypeArguments()[0]; + } + } + return null; + } + }); + return ret; + } catch (Exception e) { + LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e); + return null; + } + } + + @Override + public Class getClassForPath(List names) { + DataSchemaNode node = getSchemaNode(names); + SchemaPath path = node.getPath(); + Type type = pathToType.get(path); + if (type != null) { + type = new ReferencedTypeImpl(type.getPackageName(), type.getName()); + } else { + type = pathToInstantiatedType.get(names); + } + @SuppressWarnings("rawtypes") + WeakReference weakRef = typeToClass.get(type); + if (weakRef == null) { + LOG.error("Could not find loaded class for path: {} and type: {}", path, type.getFullyQualifiedName()); + } + return weakRef.get(); + } + + @Override + public void putPathToClass(List names, Class cls) { + Type reference = Types.typeForClass(cls); + pathToInstantiatedType.put(names, reference); + bindingClassEncountered(cls); + } + + @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; + } + + @SuppressWarnings("rawtypes") + public void bindingClassEncountered(Class cls) { + + ConcreteType typeRef = Types.typeForClass(cls); + if (typeToClass.containsKey(typeRef)) { + return; + } + LOG.trace("Binding Class {} encountered.", cls); + WeakReference weakRef = new WeakReference<>(cls); + typeToClass.put(typeRef, weakRef); + if (Augmentation.class.isAssignableFrom(cls)) { + + } else if (DataObject.class.isAssignableFrom(cls)) { + @SuppressWarnings({ "unchecked", "unused" }) + Object cdc = getCodecForDataObject((Class) cls); + } + } + + @Override + public void onClassProcessed(Class cls) { + ConcreteType typeRef = Types.typeForClass(cls); + if (typeToClass.containsKey(typeRef)) { + return; + } + LOG.trace("Binding Class {} encountered.", cls); + WeakReference weakRef = new WeakReference<>((Class) 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) { + Preconditions.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 IdentitityCodec getIdentityCodec() { + return identityRefCodec; + } + + @Override + public IdentitityCodec getCodecForIdentity(Class codec) { + bindingClassEncountered(codec); + return identityRefCodec; + } + + @Override + public void onCodecCreated(Class cls) { + CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec); + CodecMapping.setIdentityRefCodec(cls, identityRefCodec); + } + + @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 = typeToCaseCodecs.get(typeref); + + Preconditions.checkState(caseCodec != null, "Case Codec was not created proactivelly for %s", caseClass.getName()); + Preconditions.checkState(caseCodec.getSchema() != null, "Case schema is not available for %s", caseClass.getName()); + @SuppressWarnings("unchecked") + Class newCodec = generator.caseCodecFor(caseClass, caseCodec.getSchema()); + 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()); + qnamesToIdentityMap.putAll(context.getIdentities()); + for (Entry identity : context.getIdentities().entrySet()) { + typeToQname.put( + new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()), + identity.getKey()); + } + 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()); + + pathToType.put(caseNode.getKey(), caseNode.getValue()); + + ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey()); + + if (node == null) { + LOG.error("YANGTools Bug: SchemaNode for {}, with path {} was not found in context.", + typeref.getFullyQualifiedName(), caseNode.getKey()); + @SuppressWarnings("rawtypes") + ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(); + typeToCaseCodecs.putIfAbsent(typeref, value); + continue; + } + @SuppressWarnings("rawtypes") + ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node); + typeToCaseCodecs.putIfAbsent(typeref, value); + } + } + + @Override + public void onGlobalContextUpdated(SchemaContext context) { + currentSchema = context; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public void onChoiceCodecCreated(Class choiceClass, + Class, Object>> choiceCodec, ChoiceNode schema) { + ChoiceCodec oldCodec = choiceCodecs.get(choiceClass); + Preconditions.checkState(oldCodec == null); + BindingCodec, Object> delegate = newInstanceOf(choiceCodec); + ChoiceCodecImpl newCodec = new ChoiceCodecImpl(delegate); + choiceCodecs.put(choiceClass, newCodec); + CodecMapping.setClassToCaseMap(choiceCodec, (Map, BindingCodec>) classToCaseRawCodec); + CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase()); + + tryToCreateCasesCodecs(schema); + + } + + private void tryToCreateCasesCodecs(ChoiceNode schema) { + for (ChoiceCaseNode caseNode : schema.getCases()) { + SchemaPath path = caseNode.getPath(); + GeneratedTypeBuilder type; + if (path != null && (type = pathToType.get(path)) != null) { + ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); + ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref); + if (partialCodec.getSchema() == null) { + partialCodec.setSchema(caseNode); + } + + Class caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName()); + if (caseClass != null) { + getCaseCodecFor(caseClass); + } + } + } + + } + + @Override + public void onValueCodecCreated(Class valueClass, Class valueCodec) { + } + + @Override + public void onCaseCodecCreated(Class choiceClass, + Class, Object>> choiceCodec) { + } + + @Override + public void onDataContainerCodecCreated(Class dataClass, Class> dataCodec) { + if (Augmentable.class.isAssignableFrom(dataClass)) { + AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass); + CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec); + } + + } + + public 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 IntermediateMapping.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 boolean augmenting; + private BindingCodec delegate; + + private Set validNames; + private Set validQNames; + private ChoiceCaseNode schema; + + public void setSchema(ChoiceCaseNode caseNode) { + this.schema = schema; + 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(); + } + + public ChoiceCaseCodecImpl() { + this.delegate = NOT_READY_CODEC; + } + + public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) { + this.delegate = NOT_READY_CODEC; + setSchema(caseNode); + } + + @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 (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 (!Objects.equals(parent.getNamespace(), child.getNamespace()) + || !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 Collections.emptySet(); + } + + @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 BindingCodec get(Object key) { + if (!(key instanceof CompositeNode)) { + return null; + } + for (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 org.opendaylight.yangtools.yang.binding.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 Collections.emptySet(); + } + + 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 true; + } + + @Override + public Set keySet() { + return Collections.emptySet(); + } + + @Override + public Set>> entrySet() { + return Collections.emptySet(); + } + + @Override + public boolean containsValue(Object value) { + return false; + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private class AugmentableCompositeCodec implements BindingCodec { + + private final Class augmentableType; + + Map> localAugmentationCodecs = new WeakHashMap<>(); + + public AugmentableCompositeCodec(Class type) { + Preconditions.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 (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { + LOG.debug("Could not read augmentations for {}", input, e); + } + return Collections.emptyMap(); + } + + private List serializeImpl(Map input) { + List ret = new ArrayList<>(); + for (Entry entry : input.entrySet()) { + AugmentationCodec codec = getCodecForAugmentation(entry.getKey()); + CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue())); + ret.addAll(node.getChildren()); + } + return ret; + } + + public synchronized > void addAugmentationCodec(Class augmentationClass, + AugmentationCodec value) { + localAugmentationCodecs.put(augmentationClass, value); + } + + @Override + public Map deserialize(Object input) { + Map ret = new HashMap<>(); + if (input instanceof CompositeNode) { + List>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet()); + for (Entry> codec : codecs) { + ValueWithQName value = codec.getValue().deserialize((CompositeNode) input); + if (value != null && value.getValue() != null) { + ret.put(codec.getKey(), (Augmentation) value.getValue()); + } + } + } + return ret; + } + + 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); + } + } + + private static class AugmentationCodecWrapper> implements AugmentationCodec, + Delegator { + + private BindingCodec delegate; + private QName augmentationQName; + + public AugmentationCodecWrapper(BindingCodec, Object> rawCodec) { + this.delegate = rawCodec; + this.augmentationQName = BindingReflections.findQName(rawCodec.getClass()); + } + + @Override + public BindingCodec getDelegate() { + return delegate; + } + + @Override + public CompositeNode serialize(ValueWithQName input) { + @SuppressWarnings("unchecked") + List> rawValues = (List>) getDelegate().serialize(input); + List> serialized = new ArrayList<>(rawValues.size()); + for (Map val : rawValues) { + serialized.add(IntermediateMapping.toNode(val)); + } + return new CompositeNodeTOImpl(input.getQname(), null, serialized); + } + + @Override + @SuppressWarnings("unchecked") + public ValueWithQName deserialize(Node input) { + Object rawCodecValue = getDelegate().deserialize((Map) input); + return new ValueWithQName(input.getNodeType(), (T) rawCodecValue); + } + + @Override + public QName getAugmentationQName() { + return augmentationQName; + } + } + + private class IdentityCompositeCodec implements IdentitityCodec { + + @Override + public Object deserialize(Object input) { + Preconditions.checkArgument(input instanceof QName); + return deserialize((QName) input); + } + + @Override + public Class deserialize(QName input) { + Type type = qnamesToIdentityMap.get(input); + if (type == null) { + return null; + } + ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); + WeakReference softref = typeToClass.get(typeref); + if (softref == null) { + return null; + } + return softref.get(); + } + + @Override + public QName serialize(Class input) { + Preconditions.checkArgument(BaseIdentity.class.isAssignableFrom(input)); + bindingClassEncountered(input); + QName qname = identityQNames.get(input); + if (qname != null) { + return qname; + } + ConcreteType typeref = Types.typeForClass(input); + qname = typeToQname.get(typeref); + if (qname != null) { + identityQNames.put(input, qname); + } + return qname; + } + + @Override + public Object serialize(Object input) { + Preconditions.checkArgument(input instanceof Class); + return serialize((Class) input); + } + } + + public boolean isCodecAvailable(Class cls) { + if (containerCodecs.containsKey(cls)) { + return true; + } + if (identifierCodecs.containsKey(cls)) { + return true; + } + if (choiceCodecs.containsKey(cls)) { + return true; + } + if (caseCodecs.containsKey(cls)) { + return true; + } + if (augmentableCodecs.containsKey(cls)) { + return true; + } + if (augmentationCodecs.containsKey(cls)) { + return true; + } + return false; + } +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.xtend new file mode 100644 index 0000000000..0a069671d0 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.xtend @@ -0,0 +1,302 @@ +package org.opendaylight.yangtools.sal.binding.generator.impl + +import javassist.ClassPool +import org.opendaylight.yangtools.yang.model.api.SchemaContext +import org.opendaylight.yangtools.yang.model.api.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 org.opendaylight.yangtools.yang.binding.DataContainer +import java.util.concurrent.ConcurrentMap +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType +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.yangtools.yang.data.impl.codec.BindingIndependentMappingService +import org.slf4j.LoggerFactory +import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName +import org.opendaylight.yangtools.yang.data.impl.codec.DataContainerCodec +import org.opendaylight.yangtools.binding.generator.util.Types +//import org.osgi.framework.BundleContext +import java.util.Hashtable +//import org.osgi.framework.ServiceRegistration +import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException +import java.util.concurrent.Callable +import org.opendaylight.yangtools.yang.binding.Augmentation +import org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils +import org.opendaylight.yangtools.yang.data.impl.codec.AugmentationCodec +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates +import java.util.ArrayList +import org.opendaylight.yangtools.yang.data.api.Node +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl +import org.opendaylight.yangtools.yang.binding.RpcService +import java.util.Set +import org.opendaylight.yangtools.yang.common.QName +import com.google.common.collect.FluentIterable +import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil + +class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable { + + @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(); + + @Property + val ConcurrentMap> serviceTypeToRpc = new ConcurrentHashMap(); + + val promisedTypeDefinitions = HashMultimap.>create; + + val promisedSchemas = HashMultimap.>create; + + //ServiceRegistration listenerRegistration + + 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); + binding.pathToType.putAll(entry.value.childNodes) + val module = entry.key; + val context = entry.value; + updateBindingFor(context.childNodes, schemaContext); + updateBindingFor(context.cases, schemaContext); + val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module); + + if(!module.rpcs.empty) { + val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet + val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service"); + serviceTypeToRpc.put(serviceClass,rpcs); + } + + val typedefs = context.typedefs; + for (typedef : typedefs.entrySet) { + val typeRef = new ReferencedTypeImpl(typedef.value.packageName,typedef.value.name) + binding.typeDefinitions.put(typeRef, typedef.value as GeneratedType); + val schemaNode = YangSchemaUtils.findTypeDefinition(schemaContext,typedef.key); + if(schemaNode != null) { + + binding.typeToSchemaNode.put(typeRef,schemaNode); + } else { + LOG.error("Type definition for {} is not available",typedef.value); + } + + } + 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) { + + try { + val key = toDataDom(entry.key) + var CompositeNode data; + if(Augmentation.isAssignableFrom(entry.key.targetType)) { + data = toCompositeNodeImpl(key,entry.value); + } else { + data = toCompositeNodeImpl(entry.value); + } + return new SimpleEntry(key, data); + + } catch (Exception e) { + LOG.error("Error during serialization for {}.", entry.key,e); + throw e; + } + } + + 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 CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) { + + //val cls = object.implementedInterface; + //waitForSchema(cls); + val last = identifier.path.last; + val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec; + val ret = codec.serialize(new ValueWithQName(last.nodeType, object)); + if(last instanceof NodeIdentifierWithPredicates) { + val predicates = last as NodeIdentifierWithPredicates; + val newNodes = new ArrayList>(predicates.keyValues.size); + for(predicate : predicates.keyValues.entrySet) { + newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value)); + } + newNodes.addAll(ret.children); + return new CompositeNodeTOImpl(last.nodeType,null,newNodes); + } + return ret as CompositeNode; + } + + private def void waitForSchema(Class class1) { + if(Augmentation.isAssignableFrom(class1)) { + /* FIXME: We should wait also for augmentations. Currently YANGTools does not provide correct + * mapping between java Augmentation classes and augmentations. + */ + return; + } + if(registry.isCodecAvailable(class1)) { + return; + } + 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) { + dataObjectFromDataDom(path.targetType,node) as DataObject; + } + + override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) { + return tryDeserialization[ | + registry.instanceIdentifierCodec.deserialize(entry); + ] + } + + override getCodecRegistry() { + return getRegistry(); + } + + private static def T tryDeserialization(Callable deserializationBlock) throws DeserializationException { + try { + deserializationBlock.call() + } catch (Exception e) { + + // FIXME: Make this block providing more information. + throw new DeserializationException(e); + } + } + + 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) + val typeRef = new ReferencedTypeImpl(entry.value.packageName,entry.value.name) + typeToDefinition.put(typeRef, entry.value); + if (schemaNode != null) { + typeToSchemaNode.put(typeRef, schemaNode); + updatePromisedSchemas(typeRef, schemaNode); + } + + } + } + + public def void init() { + 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 +// if (ctx !== null) { +// listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable()); +// } + } + + override getRpcQNamesFor(Class service) { + return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName)); + } + + private def getSchemaWithRetry(Type type) { + val typeDef = typeToSchemaNode.get(type); + if (typeDef !== null) { + return typeDef; + } + LOG.trace("Thread blocked waiting for schema for: {}",type.fullyQualifiedName) + 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); + } + + override close() throws Exception { + //listenerRegistration?.unregister(); + } + + override dataObjectFromDataDom(Class container, CompositeNode domData) { + return tryDeserialization[ | + if (domData == null) { + return null; + } + val transformer = registry.getCodecForDataObject(container); + val ret = transformer.deserialize(domData)?.value as DataObject; + return ret; + ] + } + +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/StaticFieldInitializer.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/StaticFieldInitializer.java new file mode 100644 index 0000000000..65ed3f7719 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/StaticFieldInitializer.java @@ -0,0 +1,6 @@ +package org.opendaylight.yangtools.sal.binding.generator.impl; + +public interface StaticFieldInitializer { + + void initializeStaticFields(Class cls); +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend new file mode 100644 index 0000000000..975365081a --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend @@ -0,0 +1,1566 @@ +package org.opendaylight.yangtools.sal.binding.generator.impl + +import javassist.ClassPool +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType +import org.opendaylight.yangtools.yang.model.api.SchemaNode +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils +import javassist.CtClass +import java.util.Map +import org.opendaylight.yangtools.yang.common.QName +import javassist.CtField +import static javassist.Modifier.* +import static org.opendaylight.yangtools.sal.binding.generator.impl.CodecMapping.* +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer +import org.opendaylight.yangtools.sal.binding.model.api.Type +import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder +import org.opendaylight.yangtools.binding.generator.util.Types +import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType +import java.util.HashMap +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode +import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode +import java.util.List +import java.util.TreeSet +import com.google.common.base.Joiner +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject +import org.opendaylight.yangtools.sal.binding.model.api.Enumeration +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode +import static org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils.*; +import org.opendaylight.yangtools.yang.binding.BindingDeserializer +import org.opendaylight.yangtools.yang.binding.BindingCodec +import org.slf4j.LoggerFactory +import org.opendaylight.yangtools.sal.binding.generator.util.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 +import static extension org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils.*; +import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl +import org.opendaylight.yangtools.yang.model.util.ExtendedType +import org.opendaylight.yangtools.yang.model.util.EnumerationType +import static com.google.common.base.Preconditions.* +import org.opendaylight.yangtools.yang.model.api.SchemaPath +import javassist.CtMethod +import javassist.CannotCompileException +import java.util.concurrent.locks.Lock +import java.util.concurrent.Callable +import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils +import org.opendaylight.yangtools.yang.model.api.TypeDefinition +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition +import java.util.HashSet +import java.util.Collections +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit +import java.util.Set +import org.opendaylight.yangtools.sal.binding.generator.util.XtendHelper + +class TransformerGenerator { + + private static val log = LoggerFactory.getLogger(TransformerGenerator) + + public static val STRING = Types.typeForClass(String); + public static val BOOLEAN = Types.typeForClass(Boolean); + public static val INTEGER = Types.typeForClass(Integer); + public static val INSTANCE_IDENTIFIER = Types.typeForClass(InstanceIdentifier) + + //public static val DECIMAL = Types.typeForClass(Decimal); + public static val LONG = Types.typeForClass(Long); + + val ClassPool classPool + val extension JavassistUtils utils; + + CtClass BINDING_CODEC + + CtClass ctQName + + @Property + var File classFileCapturePath; + + @Property + var Map typeDefinitions = new ConcurrentHashMap(); + + @Property + var Map typeToDefinition = new ConcurrentHashMap(); + + @Property + var Map pathToType = new ConcurrentHashMap(); + + @Property + var Map typeToSchemaNode = new ConcurrentHashMap(); + + @Property + var Map typeToAugmentation = new ConcurrentHashMap(); + + @Property + var GeneratorListener listener; + + public static val CLASS_TYPE = Types.typeForClass(Class); + + public new(ClassPool pool) { + classPool = pool; + utils = new JavassistUtils(pool) + + BINDING_CODEC = BindingCodec.asCtClass; + ctQName = QName.asCtClass + } + + def Class, Object>> transformerFor(Class inputType) { + return withClassLoaderAndLock(inputType.classLoader, lock) [ | + val ret = getGeneratedClass(inputType) + if (ret !== null) { + listener.onClassProcessed(inputType); + return ret as Class, Object>>; + } + val ref = Types.typeForClass(inputType) + val node = typeToSchemaNode.get(ref) + val typeSpecBuilder = typeToDefinition.get(ref) + checkState(typeSpecBuilder !== null, "Could not find typedefinition for %s", inputType.name); + val typeSpec = typeSpecBuilder.toInstance(); + val newret = generateTransformerFor(inputType, typeSpec, node); + listener.onClassProcessed(inputType); + return newret as Class, Object>>; + ] + } + + def Class, Object>> transformerFor(Class inputType, DataSchemaNode node) { + return withClassLoaderAndLock(inputType.classLoader, lock) [ | + val ret = getGeneratedClass(inputType) + if (ret !== null) { + listener.onClassProcessed(inputType); + return ret as Class, Object>>; + } + val ref = Types.typeForClass(inputType) + var typeSpecBuilder = typeToDefinition.get(ref) + if (typeSpecBuilder == null) { + typeSpecBuilder = pathToType.get(node.path); + } + var schemaNode = typeToSchemaNode.get(ref); + if(schemaNode === null) { + schemaNode = node; + } + checkState(typeSpecBuilder !== null, "Could not find TypeDefinition for %s, $s", inputType.name, node); + val typeSpec = typeSpecBuilder.toInstance(); + val newret = generateTransformerFor(inputType, typeSpec, schemaNode); + listener.onClassProcessed(inputType); + 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); + listener.onClassProcessed(inputType); + 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 withClassLoaderAndLock(inputType.classLoader, lock) [ | + val transformer = getGeneratedClass(inputType) + if (transformer != null) { + return transformer; + } + val newret = generateKeyTransformerFor(inputType, type, schema); + return newret as Class, Object>>; + ] + } + + 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, DataSchemaNode node) { + val cls = loadClassWithTCCL(type.resolvedName); + transformerFor(cls, node); + } + + private def Class valueSerializer(GeneratedTransferObject type, TypeDefinition typeDefinition) { + val cls = loadClassWithTCCL(type.resolvedName); + val transformer = cls.generatedClass; + if (transformer !== null) { + return transformer; + } + var baseType = typeDefinition; + while (baseType.baseType != null) { + baseType = baseType.baseType; + } + val finalType = baseType; + return withClassLoaderAndLock(cls.classLoader, lock) [ | + val valueTransformer = generateValueTransformer(cls, type, finalType); + return valueTransformer; + ] + } + + private def Class valueSerializer(Enumeration type, TypeDefinition typeDefinition) { + val cls = loadClassWithTCCL(type.resolvedName); + val transformer = cls.generatedClass; + if (transformer !== null) { + return transformer; + } + + return withClassLoaderAndLock(cls.classLoader, lock) [ | + val valueTransformer = generateValueTransformer(cls, type); + return valueTransformer; + ] + } + + private def generateKeyTransformerFor(Class inputType, GeneratedType typeSpec, ListSchemaNode node) { + try { + + //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + val properties = typeSpec.allProperties; + val ctCls = createClass(inputType.codecClassName) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + staticQNameField(node.QName); + implementsType(BINDING_CODEC) + method(Object, "toDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + «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.resolvedName» 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); + } + ''' + ] + method(Object, "fromDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + if($2 == null){ + return null; + } + «QName.name» _localQName = $1; + java.util.Map _compositeNode = (java.util.Map) $2; + boolean _is_empty = true; + «FOR key : node.keyDefinition» + «val propertyName = key.getterName» + «val keyDef = node.getDataChildByName(key)» + «val property = properties.get(propertyName)» + «deserializeProperty(keyDef, property, propertyName)»; + «ENDFOR» + «inputType.resolvedName» _value = new «inputType.name»(«node.keyDefinition. + keyConstructorList»); + return _value; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + 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) [ + bodyChecked = ''' + return fromDomStatic(QNAME,$1); + ''' + ] + ] + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret as Class, ?>>; + } catch (Exception e) { + processException(inputType, e); + return null; + } + } + + private def Class> generateCaseCodec(Class inputType, GeneratedType type, + ChoiceCaseNode node) { + try { + + //log.info("Generating DOM Codec for {} with {}, TCCL is: {}", inputType, inputType.classLoader,Thread.currentThread.contextClassLoader) + val ctCls = createClass(type.codecClassName) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + implementsType(BINDING_CODEC) + staticQNameField(node.QName); + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, AUGMENTATION_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + method(Object, "toDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + «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, type.allProperties, node)» + return ($r) _childNodes; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + 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 + bodyChecked = deserializeBody(type, node) + ] + method(Object, "deserialize", Object) [ + bodyChecked = ''' + { + //System.out.println("«type.name»#deserialize: " +$1); + java.util.Map.Entry _input = (java.util.Map.Entry) $1; + return fromDomStatic((«QName.name»)_input.getKey(),_input.getValue()); + } + ''' + ] + ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class> + listener?.onDataContainerCodecCreated(inputType, ret); + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret; + } 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(node.QName); + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + staticField(it, AUGMENTATION_CODEC, BindingCodec) + implementsType(BINDING_CODEC) + method(Object, "toDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = serializeBodyFacade(typeSpec, node) + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + 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 + bodyChecked = deserializeBody(typeSpec, node) + ] + method(Object, "deserialize", Object) [ + bodyChecked = ''' + return fromDomStatic(QNAME,$1); + ''' + ] + ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class, Object>> + listener?.onDataContainerCodecCreated(inputType, ret); + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret; + } catch (Exception e) { + processException(inputType, e); + return null; + } + } + + private def Class, Object>> generateAugmentationTransformerFor( + Class inputType, GeneratedType type, AugmentationSchema node) { + try { + + //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + val properties = type.allProperties + val ctCls = createClass(type.codecClassName) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + staticQNameField(node.augmentationQName); + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, AUGMENTATION_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + implementsType(BINDING_CODEC) + method(Object, "toDomStatic", QName, Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + ////System.out.println("Qname " + $1); + ////System.out.println("Value " + $2); + «QName.name» _resultName = «QName.name».create(QNAME,QNAME.getLocalName()); + java.util.List _childNodes = new java.util.ArrayList(); + «type.resolvedName» value = («type.resolvedName») $2; + «FOR child : node.childNodes» + «var signature = properties.getFor(child)» + ////System.out.println("«signature.key»" + value.«signature.key»()); + «serializeProperty(child, signature.value, signature.key)» + «ENDFOR» + return ($r) _childNodes; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + 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 + bodyChecked = ''' + { + «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»(); + boolean _is_empty = true; + «FOR child : node.childNodes» + «val signature = properties.getFor(child)» + «deserializeProperty(child, signature.value, signature.key)» + _builder.«signature.key.toSetter»(«signature.key»); + «ENDFOR» + if(_is_empty) { + return null; + } + return _builder.build(); + } + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = ''' + return fromDomStatic(QNAME,$1); + ''' + ] + ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class, Object>> + listener?.onDataContainerCodecCreated(inputType, ret); + return ret; + } catch (Exception 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, IDENTITYREF_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 + bodyChecked = ''' + { + 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); + Object _ret = _codec.serialize(_input); + ////System.out.println("«typeSpec.name»#toDomStatic: " + _ret); + return («List.name») _ret; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + throw new «UnsupportedOperationException.name»("Direct invocation not supported."); + ''' + ] + method(Object, "fromDomStatic", QName, Map) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + «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) [ + bodyChecked = ''' + 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, node); + log.debug("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() + for (name : qnames) { + val fieldName = name.getterName; + names.add(fieldName); + } + return Joiner.on(",").join(names); + } + + private def serializeBodyFacade(GeneratedType type, SchemaNode node) { + val ret = serializeBody(type, node); + return ret; + } + + private def String deserializeBody(GeneratedType type, SchemaNode node) { + val ret = deserializeBodyImpl(type, node); + return ret; + } + + private def deserializeKey(GeneratedType type, ListSchemaNode node) { + if (node.keyDefinition != null && !node.keyDefinition.empty) { + return ''' + «type.resolvedName»Key getKey = («type.resolvedName»Key) «keyTransformer(type, node).canonicalName».fromDomStatic(_localQName,_compositeNode); + _builder.setKey(getKey); + '''; + } + } + + private def dispatch String deserializeBodyImpl(GeneratedType type, SchemaNode node) ''' + { + «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName()); + + if($2 == null) { + return null; + } + java.util.Map _compositeNode = (java.util.Map) $2; + «type.builderName» _builder = new «type.builderName»(); + return _builder.build(); + } + ''' + + private def dispatch String deserializeBodyImpl(GeneratedType type, ListSchemaNode node) ''' + { + «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName()); + if($2 == null) { + return null; + } + java.util.Map _compositeNode = (java.util.Map) $2; + //System.out.println(_localQName + " " + _compositeNode); + «type.builderName» _builder = new «type.builderName»(); + «deserializeKey(type, node)» + «deserializeDataNodeContainerBody(type, node)» + «deserializeAugmentations» + return _builder.build(); + } + ''' + + private def dispatch String deserializeBodyImpl(GeneratedType type, ContainerSchemaNode node) ''' + { + «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName()); + if($2 == null) { + return null; + } + java.util.Map _compositeNode = (java.util.Map) $2; + //System.out.println(_localQName + " " + _compositeNode); + «type.builderName» _builder = new «type.builderName»(); + «deserializeDataNodeContainerBody(type, node)» + «deserializeAugmentations» + return _builder.build(); + } + ''' + + private def dispatch String deserializeBodyImpl(GeneratedType type, ChoiceCaseNode node) ''' + { + «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName()); + + if($2 == null) { + return null; + } + java.util.Map _compositeNode = (java.util.Map) $2; + //System.out.println(_localQName + " " + _compositeNode); + «type.builderName» _builder = new «type.builderName»(); + «deserializeDataNodeContainerBody(type, node)» + «deserializeAugmentations» + return _builder.build(); + } + ''' + + private def deserializeDataNodeContainerBody(GeneratedType type, DataNodeContainer node) { + deserializeNodeContainerBodyImpl(type, type.allProperties, node); + } + + private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap properties, + DataNodeContainer node) { + val ret = ''' + boolean _is_empty = true; + «FOR child : node.childNodes» + «val signature = properties.getFor(child)» + «IF signature !== null» + «deserializeProperty(child, signature.value, signature.key)» + _builder.«signature.key.toSetter»(«signature.key»); + «ENDIF» + «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(); + if(_value != null) { + _builder.addAugmentation(_type,_value); + } + } + } + ''' + + private def dispatch CharSequence deserializeProperty(ListSchemaNode schema, ParameterizedType type, + String propertyName) ''' + java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName. + localName»")); + ////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_«propertyName».iterator(); + boolean _hasNext = _iterator.hasNext(); + while(_hasNext) { + Object _listItem = _iterator.next(); + _is_empty = false; + ////System.out.println(" item" + _listItem); + Object _value = «type.actualTypeArguments.get(0).serializer(schema).resolvedName».fromDomStatic(_localQName,_listItem); + ////System.out.println(" value" + _value); + «propertyName».add(_value); + _hasNext = _iterator.hasNext(); + } + } + + ////System.out.println(" list" + «propertyName»); + ''' + + private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type, + String propertyName) ''' + java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName. + localName»")); + 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_«propertyName».iterator(); + boolean _hasNext = _iterator.hasNext(); + while(_hasNext) { + _is_empty = false; + 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", schema.type)»; + «propertyName».add(_value); + } + _hasNext = _iterator.hasNext(); + } + } + ''' + + 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» «propertyName» = null; + if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) { + _is_empty = false; + java.util.Map.Entry _dom_«propertyName» = (java.util.Map.Entry) _dom_«propertyName»_list.get(0); + Object _inner_value = _dom_«propertyName».getValue(); + «propertyName» = «deserializeValue(type, "_inner_value", schema.type)»; + } + ''' + + private def dispatch CharSequence deserializeProperty(ContainerSchemaNode schema, Type type, + String propertyName) ''' + java.util.List _dom_«propertyName»_list = + _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»")); + «type.resolvedName» «propertyName» = null; + if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) { + _is_empty = false; + java.util.Map _dom_«propertyName» = (java.util.Map) _dom_«propertyName»_list.get(0); + «propertyName» = «type.serializer(schema).resolvedName».fromDomStatic(_localQName,_dom_«propertyName»); + } + ''' + + private def dispatch CharSequence deserializeProperty(ChoiceNode schema, Type type, String propertyName) ''' + «type.resolvedName» «propertyName» = «type.serializer(schema).resolvedName».fromDomStatic(_localQName,_compositeNode); + if(«propertyName» != null) { + _is_empty = false; + } + ''' + + private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter, + TypeDefinition typeDefinition) ''' + («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter») + ''' + + private def dispatch String deserializeValue(Enumeration type, String domParameter, TypeDefinition typeDefinition) ''' + («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter») + ''' + + private def dispatch Class, Object>> generateValueTransformer( + Class inputType, GeneratedTransferObject typeSpec, TypeDefinition typeDef) { + try { + + val returnType = typeSpec.valueReturnType; + if (returnType == null) { + val ctCls = createDummyImplementation(inputType, typeSpec); + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + return ret as Class, Object>>; + } + + val ctCls = createClass(typeSpec.codecClassName) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + if (inputType.isYangBindingAvailable) { + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + implementsType(BindingDeserializer.asCtClass) + } + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val ctSpec = typeSpec.asCtClass; + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); + + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1; + ////System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); + «returnType.resolvedName» _value = _encapsulatedValue.getValue(); + ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value); + Object _domValue = «serializeValue(returnType, "_value", null)»; + return _domValue; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + return toDomValue($1); + } + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + + if($1 == null) { + return null; + } + «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1", null)»; + «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(_simpleValue); + return _value; + } + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = '''{ + return fromDomValue($1); + } + ''' + ] + ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret as Class, Object>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}", inputType, e); + val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + } + + private def dispatch Class, Object>> generateValueTransformer( + Class inputType, GeneratedTransferObject typeSpec, UnionTypeDefinition typeDef) { + try { + val ctCls = createClass(typeSpec.codecClassName) [ + val properties = typeSpec.allProperties; + val getterToTypeDefinition = XtendHelper.getTypes(typeDef).toMap[type | type.QName.getterName]; + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + if (inputType.isYangBindingAvailable) { + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + implementsType(BindingDeserializer.asCtClass) + } + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val ctSpec = inputType.asCtClass; + + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); + + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1; + «FOR property : properties.entrySet» + «IF property.key != "getValue"» + «property.value.resolvedName» «property.key» = («property.value.resolvedName») _value.«property. + key»(); + if(«property.key» != null) { + return «serializeValue(property.value, property.key, getterToTypeDefinition.get(property.key))»; + } + «ENDIF» + «ENDFOR» + + return null; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + return toDomValue($1); + } + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + + if($1 == null) { + return null; + } + if($1 instanceof String) { + String _simpleValue = (String) $1; + return new «typeSpec.resolvedName»(_simpleValue.toCharArray()); + } + return null; + } + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = '''{ + return fromDomValue($1); + } + ''' + ] + ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret as Class, Object>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}", inputType, e); + val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + } + + + private def dispatch Class, Object>> generateValueTransformer( + Class inputType, GeneratedTransferObject typeSpec, BitsTypeDefinition typeDef) { + try { + val ctCls = createClass(typeSpec.codecClassName) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + if (inputType.isYangBindingAvailable) { + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + implementsType(BindingDeserializer.asCtClass) + } + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val ctSpec = typeSpec.asCtClass; + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); + + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1; + «HashSet.resolvedName» _value = new «HashSet.resolvedName»(); + //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); + + «FOR bit : typeDef.bits» + «val getter = bit.getterName()» + if(Boolean.TRUE.equals(_encapsulatedValue.«getter»())) { + _value.add("«bit.name»"); + } + «ENDFOR» + «Set.resolvedName» _domValue = «Collections.resolvedName».unmodifiableSet(_value); + //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_domValue); + + return _domValue; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + return toDomValue($1); + } + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val sortedBits = typeDef.bits.sort[o1, o2|o1.propertyName.compareTo(o2.propertyName)] + bodyChecked = ''' + { + //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + + if($1 == null) { + return null; + } + «Set.resolvedName» _domValue = («Set.resolvedName») $1; + «FOR bit : sortedBits» + Boolean «bit.propertyName» = Boolean.valueOf(_domValue.contains("«bit.name»")); + «ENDFOR» + + return new «inputType.resolvedName»(«FOR bit : sortedBits SEPARATOR ","»«bit.propertyName»«ENDFOR»); + } + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = '''{ + return fromDomValue($1); + } + ''' + ] + ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret as Class, Object>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}", inputType, e); + val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + } + + def String getPropertyName(Bit bit) { + '''_«BindingGeneratorUtil.parseToValidParamName(bit.name)»''' + } + + def String getterName(Bit bit) { + + val paramName = BindingGeneratorUtil.parseToValidParamName(bit.name); + return '''is«paramName.toFirstUpper»'''; + } + + def boolean isYangBindingAvailable(Class class1) { + try { + val bindingCodecClass = class1.classLoader.loadClass(BINDING_CODEC.name); + return bindingCodecClass !== null; + } catch (ClassNotFoundException e) { + return false; + } + } + + private def createDummyImplementation(Class object, GeneratedTransferObject typeSpec) { + log.trace("Generating Dummy DOM Codec for {} with {}", object, object.classLoader) + return createClass(typeSpec.codecClassName) [ + if (object.isYangBindingAvailable) { + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + implementsType(BindingDeserializer.asCtClass) + } + //implementsType(BindingDeserializer.asCtClass) + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = '''{ + if($1 == null) { + return null; + } + return $1.toString(); + + }''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + return toDomValue($1); + } + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = '''return null;''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = '''{ + return fromDomValue($1); + } + ''' + ] + ] + } + + private def Type getValueReturnType(GeneratedTransferObject object) { + for (prop : object.properties) { + if (prop.name == "value") { + return prop.returnType; + } + } + if (object.superType != null) { + return getValueReturnType(object.superType); + } + return null; + } + + private def Class generateValueTransformer(Class inputType, Enumeration typeSpec) { + try { + val typeRef = new ReferencedTypeImpl(typeSpec.packageName, typeSpec.name); + val schema = typeToSchemaNode.get(typeRef) as ExtendedType; + val enumSchema = schema.baseType as EnumerationType; + + //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + val ctCls = createClass(typeSpec.codecClassName) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + //implementsType(BINDING_CODEC) + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = '''{ + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1; + «FOR en : enumSchema.values» + if(«typeSpec.resolvedName».«BindingGeneratorUtil.parseToClassName(en.name)».equals(_value)) { + return "«en.name»"; + } + «ENDFOR» + return null; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + return toDomValue($1); + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + if($1 == null) { + return null; + } + String _value = (String) $1; + «FOR en : enumSchema.values» + if("«en.name»".equals(_value)) { + return «typeSpec.resolvedName».«BindingGeneratorUtil.parseToClassName(en.name)»; + } + «ENDFOR» + return null; + } + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = ''' + return fromDomValue($1); + ''' + ] + ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret; + } catch (CodeGenerationException e) { + throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e); + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}", inputType, e); + val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + + } + + def Class toClassImpl(CtClass newClass, ClassLoader loader, ProtectionDomain domain) { + 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); + captureFile.createNewFile + + } + + private def dispatch String deserializeValue(Type type, String domParameter, TypeDefinition typeDef) { + if (INSTANCE_IDENTIFIER.equals(type)) { + return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)''' + } else if (CLASS_TYPE.equals(type)) { + return '''(«Class.name») «IDENTITYREF_CODEC».deserialize(«domParameter»)''' + } + return '''(«type.resolvedName») «domParameter»''' + + } + + /** + * Default catch all + * + **/ + private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, String propertyName) ''' + «type.resolvedName» «propertyName» = null; + ''' + + private def dispatch CharSequence deserializeProperty(DataSchemaNode container, GeneratedTypeBuilder type, + String propertyName) { + _deserializeProperty(container, type.toInstance, propertyName) + } + + public static def toSetter(String it) { + + if (startsWith("is")) { + return "set" + substring(2); + } else if (startsWith("get")) { + return "set" + substring(3); + } + return "set" + it; + } + + /* + private def dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, 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, QName node) { + val field = new CtField(ctQName, "QNAME", it); + field.modifiers = PUBLIC + FINAL + STATIC; + addField(field, + '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''') + } + + private def dispatch String serializeBody(GeneratedType type, ListSchemaNode node) ''' + { + «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName()); + java.util.List _childNodes = new java.util.ArrayList(); + «type.resolvedName» value = («type.resolvedName») $2; + «transformDataContainerBody(type, type.allProperties, node)» + «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(); + «type.resolvedName» value = («type.resolvedName») $2; + «transformDataContainerBody(type, type.allProperties, node)» + «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(); + «type.resolvedName» value = («type.resolvedName») $2; + «transformDataContainerBody(type, type.allProperties, node)» + «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(); + «type.resolvedName» value = («type.resolvedName») $2; + return ($r) java.util.Collections.singletonMap(_resultName,_childNodes); + } + ''' + + private def transformDataContainerBody(Type type, Map properties, DataNodeContainer node) { + val ret = ''' + «FOR child : node.childNodes» + «val signature = properties.getFor(child)» + «IF signature !== null» + ////System.out.println("«type.name»#«signature.key»" + value.«signature.key»()); + «serializeProperty(child, signature.value, signature.key)» + «ENDIF» + «ENDFOR» + ''' + return ret; + } + + private 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) { + var sig = map.get(node.getterName); + if (sig != null) { + return new SimpleEntry(node.getterName, sig); + } + sig = map.get(node.booleanGetterName); + if (sig != null) { + return new SimpleEntry(node.booleanGetterName, map.get(node.booleanGetterName)); + } + return null; + } + + private static def String getBooleanGetterName(DataSchemaNode node) { + return "is" + BindingGeneratorUtil.parseToClassName(node.QName.localName); + } + + private static def String getGetterName(DataSchemaNode node) { + return "get" + BindingGeneratorUtil.parseToClassName(node.QName.localName); + } + + private static def String getGetterName(QName node) { + return "get" + BindingGeneratorUtil.parseToClassName(node.localName); + } + + private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type, + String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); + ////System.out.println("«propertyName»:" + «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(schema).resolvedName».toDomStatic(_resultName,_listItem); + _childNodes.add(_domValue); + _hasNext = _iterator.hasNext(); + } + } + ''' + + private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); + + if(«propertyName» != null) { + «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»"); + Object _propValue = «serializeValue(type, propertyName, schema.type)»; + if(_propValue != null) { + Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); + _childNodes.add(_domValue); + } + } + ''' + + private def dispatch serializeValue(GeneratedTransferObject type, String parameter, TypeDefinition typeDefinition) { + '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)''' + } + + private def dispatch serializeValue(Enumeration type, String parameter, TypeDefinition typeDefinition) { + '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)''' + } + + private def dispatch serializeValue(Type signature, String property, TypeDefinition typeDefinition) { + if (INSTANCE_IDENTIFIER == signature) { + return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)''' + } else if (CLASS_TYPE.equals(signature)) { + return '''(«QName.resolvedName») «IDENTITYREF_CODEC».serialize(«property»)''' + } + if ("char[]" == signature.name) { + return '''new String(«property»)'''; + } + return '''«property»'''; + } + + 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 = «serializeValue(type.actualTypeArguments.get(0), "_listItem", schema.type)»; + Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); + _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(container).resolvedName».toDomStatic(_resultName,«propertyName»); + _childNodes.addAll(domValue); + } + ''' + + /** + * Default catch all + * + **/ + 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, + String propertyName) { + serializeProperty(container, type.toInstance, propertyName) + } + + private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedType type, + String propertyName) ''' + «type.resolvedName» «propertyName» = value.«propertyName»(); + if(«propertyName» != null) { + Object domValue = «type.serializer(container).resolvedName».toDomStatic(_resultName,«propertyName»); + _childNodes.add(domValue); + } + ''' + + private def codecClassName(GeneratedType typeSpec) { + return '''«typeSpec.resolvedName»$Broker$Codec$DOM''' + } + + private def codecClassName(Class typeSpec) { + return '''«typeSpec.name»$Broker$Codec$DOM''' + } + + private def HashMap getAllProperties(GeneratedType type) { + val ret = new HashMap(); + type.collectAllProperties(ret); + return ret; + } + + private def dispatch void collectAllProperties(GeneratedType type, Map set) { + for (definition : type.methodDefinitions) { + set.put(definition.name, definition.returnType); + } + for (property : type.properties) { + set.put(property.getterName, property.returnType); + } + for (parent : type.implements) { + parent.collectAllProperties(set); + } + } + + def String getGetterName(GeneratedProperty property) { + return "get" + property.name.toFirstUpper + } + + private def dispatch void collectAllProperties(Type type, Map set) { + // NOOP for generic type. + } + + def String getResolvedName(Type type) { + return type.asCtClass.name; + } + + def String getResolvedName(Class type) { + return type.asCtClass.name; + } + + def CtClass asCtClass(Type type) { + 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); + 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); + throw exception; + } + + private def setBodyChecked(CtMethod method, String body) { + try { + method.setBody(body); + } catch (CannotCompileException e) { + log.error("Cannot compile method: {}#{} {}, Reason: {} Body: {}", method.declaringClass, method.name, + method.signature, e.message, body) + throw e; + } + } + + private def V withClassLoaderAndLock(ClassLoader cls, Lock lock, Callable function) throws Exception { + appendClassLoaderIfMissing(cls); + ClassLoaderUtils.withClassLoaderAndLock(cls, lock, function); + } + +} + +@Data +class PropertyPair { + + String getterName; + + Type type; + + @Property + Type returnType; + @Property + SchemaNode schemaNode; +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassGenerator.java new file mode 100644 index 0000000000..03adb87504 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassGenerator.java @@ -0,0 +1,7 @@ +package org.opendaylight.yangtools.sal.binding.generator.util; + +import javassist.CtClass; + +public interface ClassGenerator { + void process(CtClass cls); +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java new file mode 100644 index 0000000000..faf0eeb101 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java @@ -0,0 +1,85 @@ +package org.opendaylight.yangtools.sal.binding.generator.util; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.locks.Lock; + +import com.google.common.base.Joiner; +import com.google.common.base.Optional; + +public final class ClassLoaderUtils { + + private ClassLoaderUtils() { + throw new UnsupportedOperationException("Utility class"); + } + + public static V withClassLoader(ClassLoader cls, Callable function) throws Exception { + 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); + return function.call(); + } finally { + Thread.currentThread().setContextClassLoader(oldCls); + if (lock.isPresent()) { + lock.get().unlock(); + } + } + } + + public static Object construct(Constructor constructor, List objects) + throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Object[] initargs = objects.toArray(new Object[] {}); + return constructor.newInstance(initargs); + } + + public static Class loadClassWithTCCL(String name) throws ClassNotFoundException { + if ("byte[]".equals(name)) { + return byte[].class; + } else if("char[]".equals(name)) { + return char[].class; + } + try { + return Thread.currentThread().getContextClassLoader().loadClass(name); + } catch (ClassNotFoundException e) { + String[] components = name.split("\\."); + String potentialOuter; + int length = components.length; + if (length > 2 && (potentialOuter = components[length - 2]) != null && Character.isUpperCase(potentialOuter.charAt(0))) { + + String outerName = Joiner.on(".").join(Arrays.asList(components).subList(0, length - 1)); + String innerName = outerName + "$" + components[length-1]; + return Thread.currentThread().getContextClassLoader().loadClass(innerName); + } else { + throw e; + } + } + } + + public static Class tryToLoadClassWithTCCL(String fullyQualifiedName) { + try { + return loadClassWithTCCL(fullyQualifiedName); + } catch (ClassNotFoundException e) { + return null; + } + } +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/CodeGenerationException.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/CodeGenerationException.java new file mode 100644 index 0000000000..561d88c31f --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/CodeGenerationException.java @@ -0,0 +1,25 @@ +package org.opendaylight.yangtools.sal.binding.generator.util; + +public class CodeGenerationException extends RuntimeException{ + + public CodeGenerationException() { + super(); + } + + public CodeGenerationException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public CodeGenerationException(String message, Throwable cause) { + super(message, cause); + } + + public CodeGenerationException(String message) { + super(message); + } + + public CodeGenerationException(Throwable cause) { + super(cause); + } +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/FieldGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/FieldGenerator.java new file mode 100644 index 0000000000..f359e64306 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/FieldGenerator.java @@ -0,0 +1,7 @@ +package org.opendaylight.yangtools.sal.binding.generator.util; + +import javassist.CtField; + +public interface FieldGenerator { + void process(CtField field); +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.xtend new file mode 100644 index 0000000000..c45e0558b2 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/JavassistUtils.xtend @@ -0,0 +1,128 @@ +package org.opendaylight.yangtools.sal.binding.generator.util + +import javassist.CtClass +import javassist.CtMethod +import javassist.ClassPool +import java.util.Arrays +import static com.google.common.base.Preconditions.*; +import javassist.CtField +import javassist.Modifier +import javassist.NotFoundException +import javassist.LoaderClassPath +import javassist.ClassClassPath +import java.util.concurrent.locks.Lock +import java.util.concurrent.locks.ReentrantLock +import org.slf4j.LoggerFactory +import java.util.HashMap +import java.util.WeakHashMap + +class JavassistUtils { + + private static val LOG = LoggerFactory.getLogger(JavassistUtils); + + private val loaderClassPaths = new WeakHashMap(); + + ClassPool classPool + + @Property + val Lock lock = new ReentrantLock(); + + new(ClassPool pool) { + classPool = pool; + } + + def void method(CtClass it, Class returnType, String name, Class parameter, MethodGenerator function1) { + val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it); + function1.process(method); + it.addMethod(method); + } + + def void method(CtClass it, Class returnType, String name, Class parameter1, Class parameter2, MethodGenerator function1) { + val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter1.asCtClass,parameter2.asCtClass), it); + function1.process(method); + it.addMethod(method); + } + + + def void staticMethod(CtClass it, Class returnType, String name, Class parameter, MethodGenerator function1) { + val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it); + function1.process(method); + it.addMethod(method); + } + + def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) { + for (method : source.methods) { + if (method.declaringClass == source) { + val redeclaredMethod = new CtMethod(method, target, null); + function1.process(redeclaredMethod); + target.addMethod(redeclaredMethod); + } + } + } + + def CtClass createClass(String fqn, ClassGenerator cls) { + + val target = classPool.makeClass(fqn); + cls.process(target); + return target; + } + + def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) { + + val target = classPool.makeClass(fqn); + target.implementsType(superInterface); + cls.process(target); + return target; + } + + def void implementsType(CtClass it, CtClass supertype) { + checkArgument(supertype.interface, "Supertype must be interface"); + addInterface(supertype); + } + + def asCtClass(Class class1) { + classPool.get(class1); + } + + def CtField field(CtClass it, String name, Class returnValue) { + val field = new CtField(returnValue.asCtClass, name, it); + field.modifiers = Modifier.PUBLIC + addField(field); + return field; + } + + def 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 { + return pool.get(cls.name) + } catch (NotFoundException e) { + appendClassLoaderIfMissing(cls.classLoader) + try { + return pool.get(cls.name) + } catch (NotFoundException ef) { + LOG.warn("Appending ClassClassPath for {}",cls); + pool.appendClassPath(new ClassClassPath(cls)); + + return pool.get(cls.name) + } + } + } + + def void appendClassLoaderIfMissing(ClassLoader loader) { + if(loaderClassPaths.containsKey(loader)) { + return; + } + val ctLoader = new LoaderClassPath(loader); + classPool.appendClassPath(ctLoader); + } + + def void ensureClassLoader(Class child) { + appendClassLoaderIfMissing(child.classLoader); + } +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/MethodGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/MethodGenerator.java new file mode 100644 index 0000000000..046cb8b69c --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/MethodGenerator.java @@ -0,0 +1,7 @@ +package org.opendaylight.yangtools.sal.binding.generator.util; + +import javassist.CtMethod; + +public interface MethodGenerator { + void process(CtMethod method); +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/XtendHelper.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/XtendHelper.java new file mode 100644 index 0000000000..fc5b27c49e --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/XtendHelper.java @@ -0,0 +1,14 @@ +package org.opendaylight.yangtools.sal.binding.generator.util; + +import java.util.List; + +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; + +public class XtendHelper { + + @SuppressWarnings({"rawtypes","unchecked"}) + public static Iterable getTypes(UnionTypeDefinition definition) { + return (Iterable) (List) definition.getTypes(); + } +} diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/YangSchemaUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/YangSchemaUtils.java new file mode 100644 index 0000000000..30acf1efc1 --- /dev/null +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/YangSchemaUtils.java @@ -0,0 +1,63 @@ +package org.opendaylight.yangtools.sal.binding.generator.util; + +import java.util.List; + +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.*; + +import com.google.common.base.Preconditions; + +public class YangSchemaUtils { + + public static final String AUGMENT_IDENTIFIER = "augment-identifier"; + + + public YangSchemaUtils() { + throw new UnsupportedOperationException("Helper class. Instantiation is prohibited"); + } + + + public static QName getAugmentationQName(AugmentationSchema augmentation) { + Preconditions.checkNotNull(augmentation, "Augmentation must not be null."); + QName identifier = getAugmentationIdentifier(augmentation); + if(identifier != null) { + return identifier; + } + for(DataSchemaNode child : augmentation.getChildNodes()) { + // FIXME: Return true name + return QName.create(child.getQName(), "foo_augment"); + } + // FIXME: Allways return a qname with module namespace. + return null; + } + + public static QName getAugmentationIdentifier(AugmentationSchema augmentation) { + for(UnknownSchemaNode extension : augmentation.getUnknownSchemaNodes()) { + if(AUGMENT_IDENTIFIER.equals(extension.getNodeType().getLocalName())) { + return extension.getQName(); + } + } + return null; + } + + + public static TypeDefinition findTypeDefinition(SchemaContext context, SchemaPath path) { + List arguments = path.getPath(); + QName first = arguments.get(0); + QName typeQName = arguments.get(arguments.size() -1); + DataNodeContainer previous = context.findModuleByNamespaceAndRevision(first.getNamespace(), first.getRevision()); + if(previous == null) { + return null; + } + Preconditions.checkArgument(arguments.size() == 1); + for (QName qName : arguments) { + //previous.getDataChildByName(qName); + } + for(TypeDefinition typedef : previous.getTypeDefinitions()) { + if(typedef.getQName().equals(typeQName)) { + return typedef; + } + } + return null; + } +} diff --git a/code-generator/pom.xml b/code-generator/pom.xml index 064739c506..e1b4c2e9a8 100644 --- a/code-generator/pom.xml +++ b/code-generator/pom.xml @@ -25,7 +25,13 @@ - + + org.javassist + javassist + ${javassist.version} + + + org.opendaylight.yangtools binding-model-api @@ -73,6 +79,11 @@ yang-data-api ${project.version} + + org.opendaylight.yangtools + yang-data-impl + ${project.version} + org.opendaylight.yangtools yang-data-util @@ -118,7 +129,7 @@ - + org.apache.felix maven-bundle-plugin diff --git a/pom.xml b/pom.xml index 2725b2d198..b0a4b7601f 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,7 @@ 2.4.3 2.1.6 1.9.5 + 3.17.1-GA @@ -188,7 +189,7 @@ ${maven.jar.version} - ${project.build.outputDirectory}/META-INF/MANIFEST.MF diff --git a/yang/yang-data-impl/pom.xml b/yang/yang-data-impl/pom.xml index a6958ba9be..31dee339d7 100644 --- a/yang/yang-data-impl/pom.xml +++ b/yang/yang-data-impl/pom.xml @@ -39,6 +39,10 @@ ${project.groupId} yang-data-api + + ${project.groupId} + yang-binding + ${project.groupId} yang-parser-impl diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/AugmentationCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/AugmentationCodec.java new file mode 100644 index 0000000000..a5127d7027 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/AugmentationCodec.java @@ -0,0 +1,18 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.common.QName; +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); + + public QName getAugmentationQName(); +} diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/BindingIndependentMappingService.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/BindingIndependentMappingService.java new file mode 100644 index 0000000000..7c22be7d18 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/BindingIndependentMappingService.java @@ -0,0 +1,32 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +import java.util.Map.Entry; +import java.util.Set; + +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +public interface BindingIndependentMappingService { + + CodecRegistry getCodecRegistry(); + + CompositeNode toDataDom(DataObject data); + + Entry toDataDom( + Entry, DataObject> entry); + + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(InstanceIdentifier path); + + DataObject dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result) throws DeserializationException; + + InstanceIdentifier fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) throws DeserializationException; + + Set getRpcQNamesFor(Class service); + + DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput); + +} diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCaseCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCaseCodec.java new file mode 100644 index 0000000000..839ae30b56 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCaseCodec.java @@ -0,0 +1,16 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCodec.java new file mode 100644 index 0000000000..c255290124 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ChoiceCodec.java @@ -0,0 +1,12 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/CodecRegistry.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/CodecRegistry.java new file mode 100644 index 0000000000..938dcd650e --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/CodecRegistry.java @@ -0,0 +1,39 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +import java.util.List; + +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.common.QName; + + +public interface CodecRegistry { + + InstanceIdentifierCodec getInstanceIdentifierCodec(); + + IdentitityCodec getIdentityCodec(); + + DataContainerCodec getCodecForDataObject(Class object); + + > IdentifierCodec getIdentifierCodecForIdentifiable(Class object); + + > IdentifierCodec getCodecForIdentifier(Class object); + + > AugmentationCodec getCodecForAugmentation(Class object); + + IdentitityCodec getCodecForIdentity(Class codec); + + Class getClassForPath(List names); + + IdentifierCodec getKeyCodecForPath(List names); + + + void bindingClassEncountered(Class cls); + + void putPathToClass(List names, Class cls); + + public abstract QName getQNameForAugmentation(Class cls); +} diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DataContainerCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DataContainerCodec.java new file mode 100644 index 0000000000..6e6e9685b1 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DataContainerCodec.java @@ -0,0 +1,15 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +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 DataContainerCodec extends DomCodec { + + + @Override + public ValueWithQName deserialize(Node input); + + @Override + public CompositeNode serialize(ValueWithQName input); +} diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DeserializationException.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DeserializationException.java new file mode 100644 index 0000000000..cf1d3fde7e --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DeserializationException.java @@ -0,0 +1,24 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +public class DeserializationException extends Exception { + + public DeserializationException() { + } + + public DeserializationException(String message) { + super(message); + } + + public DeserializationException(Throwable cause) { + super(cause); + } + + public DeserializationException(String message, Throwable cause) { + super(message, cause); + } + + public DeserializationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DomCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DomCodec.java new file mode 100644 index 0000000000..c681b2ccd6 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/DomCodec.java @@ -0,0 +1,16 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +import org.opendaylight.yangtools.yang.binding.BindingCodec; +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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentifierCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentifierCodec.java new file mode 100644 index 0000000000..b8bab878e0 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentifierCodec.java @@ -0,0 +1,14 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentitityCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentitityCodec.java new file mode 100644 index 0000000000..649804c3dc --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/IdentitityCodec.java @@ -0,0 +1,14 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.common.QName; + +public interface IdentitityCodec extends BindingCodec>{ + + @Override + public QName serialize(Class input); + + @Override + public Class deserialize(QName input); +} diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/InstanceIdentifierCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/InstanceIdentifierCodec.java new file mode 100644 index 0000000000..1d58e8caa4 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/InstanceIdentifierCodec.java @@ -0,0 +1,13 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +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/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ValueWithQName.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ValueWithQName.java new file mode 100644 index 0000000000..b2097da109 --- /dev/null +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/ValueWithQName.java @@ -0,0 +1,72 @@ +package org.opendaylight.yangtools.yang.data.impl.codec; + +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/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaServiceListener.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaServiceListener.java new file mode 100644 index 0000000000..a4cf027c7a --- /dev/null +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaServiceListener.java @@ -0,0 +1,12 @@ +package org.opendaylight.yangtools.yang.model.api; + +import java.util.EventListener; + +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +// TODO rename to schemaContextListener +public interface SchemaServiceListener extends EventListener { + + void onGlobalContextUpdated(SchemaContext context); + +} -- 2.36.6