From 75d1045781cc09d0aa0e509a21281f734a687e7a Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Tue, 31 Mar 2015 14:57:44 +0200 Subject: [PATCH] Bug 2374 - YANG Binding: Added support for AugmentationHolder interface Binding specification v1 was originally designed and implemented in only one implementation of interfaces in mind, which were generated one, but during Helium additional implementation was introduced, but specification and generated copy builder constructor did not accounted for that change. Added additional interface which is implemented by LazyDataObject that allow copy of augmenations. Updated code generator to allow for that change and implementation of LazyDataObject to support new interface contract. Change-Id: I15aec38259f7f5e95301368d0264dfcf0571e2ba Signed-off-by: Tony Tkacik --- .../codec/impl/DataObjectCodecContext.java | 10 +++-- .../data/codec/impl/LazyDataObject.java | 3 ++ .../test/AugmentationSubstitutionTest.java | 31 +++++++++---- .../java/api/generator/BuilderTemplate.xtend | 42 ++++++++++-------- .../yang/binding/AugmentationHolder.java | 32 ++++++++++++++ .../binding/util/AugmentationFieldGetter.java | 43 ++++++++++++------- 6 files changed, 114 insertions(+), 47 deletions(-) create mode 100644 yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/AugmentationHolder.java diff --git a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java index 074a20a790..8302aed0e6 100644 --- a/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java +++ b/code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecContext.java @@ -7,6 +7,8 @@ */ package org.opendaylight.yangtools.binding.data.codec.impl; +import org.opendaylight.yangtools.yang.binding.AugmentationHolder; + import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; @@ -116,7 +118,7 @@ abstract class DataObjectCodecContext proxyClass = Proxy.getProxyClass(getBindingClass().getClassLoader(), new Class[] { getBindingClass() }); + final Class proxyClass = Proxy.getProxyClass(getBindingClass().getClassLoader(), new Class[] { getBindingClass(), AugmentationHolder.class }); try { proxyConstructor = LOOKUP.findConstructor(proxyClass, CONSTRUCTOR_TYPE).asType(DATAOBJECT_TYPE); } catch (NoSuchMethodException | IllegalAccessException e) { @@ -161,7 +163,7 @@ abstract class DataObjectCodecContext Optional> possibleStreamChild( - Class childClass) { + final Class childClass) { final DataContainerCodecPrototype childProto = byStreamClass.get(childClass); if(childProto != null) { return Optional.>of((DataContainerCodecContext) childProto.get()); @@ -310,13 +312,13 @@ abstract class DataObjectCodecContext implements InvocationHandler, Augment private static final String EQUALS = "equals"; private static final String GET_AUGMENTATION = "getAugmentation"; private static final String HASHCODE = "hashCode"; + private static final String AUGMENTATIONS = "augmentations"; private static final Object NULL_VALUE = new Object(); private final ConcurrentHashMap cachedData = new ConcurrentHashMap<>(); @@ -62,6 +63,8 @@ class LazyDataObject implements InvocationHandler, Augment return bindingToString(); } else if (HASHCODE.equals(name)) { return bindingHashCode(); + } else if (AUGMENTATIONS.equals(name)) { + return getAugmentationsImpl(); } return getBindingData(method); } else if (GET_AUGMENTATION.equals(method.getName())) { diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java index 6dc53e5f8f..32006821d4 100644 --- a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java +++ b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/AugmentationSubstitutionTest.java @@ -7,6 +7,10 @@ */ package org.opendaylight.yangtools.binding.data.codec.test; +import static org.junit.Assert.assertEquals; + +import com.google.common.base.Optional; +import java.util.Collections; import javassist.ClassPool; import org.junit.Test; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.augment.rev140709.RpcComplexUsesAugment; @@ -27,10 +31,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import java.util.Collections; - -import static org.junit.Assert.assertEquals; - public class AugmentationSubstitutionTest extends AbstractBindingRuntimeTest { @@ -48,26 +48,39 @@ public class AugmentationSubstitutionTest extends AbstractBindingRuntimeTest { @Override public void setup() { super.setup(); - JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault()); + final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault()); registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils)); registry.onBindingRuntimeContextUpdated(getRuntimeContext()); } @Test public void augmentationInGroupingSubstituted() { - TopLevelList baRpc = new TopLevelListBuilder() + final TopLevelList baRpc = new TopLevelListBuilder() .setKey(TOP_FOO_KEY) .addAugmentation(RpcComplexUsesAugment.class, new RpcComplexUsesAugmentBuilder(createComplexData()).build()) .build(); - TopLevelList baTree = new TopLevelListBuilder() + final TopLevelList baTree = new TopLevelListBuilder() .setKey(TOP_FOO_KEY) .addAugmentation(TreeComplexUsesAugment.class, new TreeComplexUsesAugmentBuilder(createComplexData()).build()) .build(); - NormalizedNode domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baTree).getValue(); - NormalizedNode domRpcEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baRpc).getValue(); + final NormalizedNode domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baTree).getValue(); + final NormalizedNode domRpcEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baRpc).getValue(); assertEquals(domTreeEntry, domRpcEntry); } + @Test + public void copyBuilderWithAugmenationsTest() { + final TopLevelList manuallyConstructed = new TopLevelListBuilder() + .setKey(TOP_FOO_KEY) + .addAugmentation(TreeComplexUsesAugment.class, new TreeComplexUsesAugmentBuilder(createComplexData()).build()) + .build(); + final NormalizedNode domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, manuallyConstructed).getValue(); + final TopLevelList deserialized = registry.deserializeFunction(BA_TOP_LEVEL_LIST).apply(Optional.>of(domTreeEntry)).get(); + assertEquals(manuallyConstructed, deserialized); + final TopLevelList copiedFromDeserialized = new TopLevelListBuilder(deserialized).build(); + assertEquals(manuallyConstructed, copiedFromDeserialized); + } + private RpcComplexUsesAugment createComplexData() { return new RpcComplexUsesAugmentBuilder() .setContainerWithUses(new ContainerWithUsesBuilder() diff --git a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend index 15e9375657..710f102210 100644 --- a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend +++ b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend @@ -32,6 +32,7 @@ import org.opendaylight.yangtools.yang.binding.Augmentable import org.opendaylight.yangtools.yang.binding.DataObject import org.opendaylight.yangtools.yang.binding.Identifiable import org.opendaylight.yangtools.concepts.Builder +import org.opendaylight.yangtools.yang.binding.AugmentationHolder /** * Template for generating JAVA builder classes. @@ -556,25 +557,28 @@ class BuilderTemplate extends BaseTemplate { this.«field.fieldName» = base.«field.getterMethodName»(); «ENDFOR» «IF augmentField != null» - «IF !impl»if (base instanceof «type.name»«IMPL») {«ENDIF» - «IF !impl»«type.name»«IMPL» _impl = («type.name»«IMPL») base;«ENDIF» - «val prop = if (impl) "base" else "_impl"» - «IF impl» - switch («prop».«augmentField.name».size()) { - case 0: - this.«augmentField.name» = «Collections.importedName».emptyMap(); - break; - case 1: - final «Map.importedName».Entry<«Class.importedName», «augmentField.returnType.importedName»> e = «prop».«augmentField.name».entrySet().iterator().next(); - this.«augmentField.name» = «Collections.importedName».<«Class.importedName», «augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue()); - break; - default : - this.«augmentField.name» = new «HashMap.importedName»<>(«prop».«augmentField.name»); - } - «ELSE» - this.«augmentField.name» = new «HashMap.importedName»<>(«prop».«augmentField.name»); - «ENDIF» - «IF !impl»}«ENDIF» + «IF impl» + switch (base.«augmentField.name».size()) { + case 0: + this.«augmentField.name» = «Collections.importedName».emptyMap(); + break; + case 1: + final «Map.importedName».Entry<«Class.importedName», «augmentField.returnType.importedName»> e = base.«augmentField.name».entrySet().iterator().next(); + this.«augmentField.name» = «Collections.importedName».<«Class.importedName», «augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue()); + break; + default : + this.«augmentField.name» = new «HashMap.importedName»<>(base.«augmentField.name»); + } + «ELSE» + if (base instanceof «type.name»«IMPL») { + «type.name»«IMPL» impl = («type.name»«IMPL») base; + this.«augmentField.name» = new «HashMap.importedName»<>(impl.«augmentField.name»); + } else if (base instanceof «AugmentationHolder.importedName») { + @SuppressWarnings("unchecked") + «AugmentationHolder.importedName»<«type.importedName»> casted =(«AugmentationHolder.importedName»<«type.importedName»>) base; + this.«augmentField.name» = new «HashMap.importedName»<>(casted.augmentations()); + } + «ENDIF» «ENDIF» } ''' diff --git a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/AugmentationHolder.java b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/AugmentationHolder.java new file mode 100644 index 0000000000..472c3c28c8 --- /dev/null +++ b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/AugmentationHolder.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.yang.binding; + +import java.util.Map; + +/** + * + * Augmentable (extensible) object which could carry additional data defined by + * third-party extension, without introducing conflict between various + * extension. + * + * + * @author Tony Tkacik + * @param + * Base class which should is target + * for augmentations. + */ +public interface AugmentationHolder { + + /** + * Returns map of all augmentations. + * + * @return map of all augmentations. + */ + Map>,Augmentation> augmentations(); +} diff --git a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/AugmentationFieldGetter.java b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/AugmentationFieldGetter.java index 8178d8f1e1..2e8a33a272 100644 --- a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/AugmentationFieldGetter.java +++ b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/AugmentationFieldGetter.java @@ -1,12 +1,14 @@ /* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html + * This program and the accompanying materials are made available under the terms of the Eclipse + * Public License v1.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.yang.binding.util; +import org.opendaylight.yangtools.yang.binding.AugmentationHolder; + import com.google.common.base.Preconditions; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -30,19 +32,31 @@ abstract class AugmentationFieldGetter { } }; - /** - * - * Retrieves augmentations from supplied object - * - * @param input Input Data object, from which augmentations should be extracted - * @return Map of Augmentation class to augmentation - */ - protected abstract Map>, Augmentation> getAugmentations(final Object input); + private static final AugmentationFieldGetter AUGMENTATION_HOLDER_GETTER = new AugmentationFieldGetter() { - private static final LoadingCache, AugmentationFieldGetter> AUGMENTATION_GETTERS = - CacheBuilder.newBuilder().weakKeys().softValues().build(new AugmentationGetterLoader()); + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + protected Map>, Augmentation> getAugmentations(final Object input) { + return (Map) ((AugmentationHolder) input).augmentations(); + } + }; + + /** + * + * Retrieves augmentations from supplied object + * + * @param input Input Data object, from which augmentations should be extracted + * @return Map of Augmentation class to augmentation + */ + protected abstract Map>, Augmentation> getAugmentations(final Object input); + + private static final LoadingCache, AugmentationFieldGetter> AUGMENTATION_GETTERS = CacheBuilder + .newBuilder().weakKeys().softValues().build(new AugmentationGetterLoader()); public static AugmentationFieldGetter getGetter(final Class clz) { + if(AugmentationHolder.class.isAssignableFrom(clz)) { + return AUGMENTATION_HOLDER_GETTER; + } return AUGMENTATION_GETTERS.getUnchecked(clz); } @@ -81,5 +95,4 @@ abstract class AugmentationFieldGetter { } } - } -- 2.36.6