Rework DataObjectSerializer implementations 09/81709/20
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 20 Apr 2019 12:03:42 +0000 (14:03 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 29 Apr 2019 08:23:33 +0000 (10:23 +0200)
This patch rework generation of DataObjectSerializers to base
them on a common superclass and generates them into a target
CodecClassLoader.

This removes pollution of class loaders, while maintaining the
same level of functionality with slightly less byte code.

It also cleans up external interfaces, as the serializers
generation is a purely-internal implementation detail and is not
exposed to outside world -- hence this patch deprecates all
classes and interfaces involved in that former leak.

JIRA: MDSAL-401
Change-Id: I80daff7e05e7487af7dca4e4bdae6b2893c97037
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
38 files changed:
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingToNormalizedNodeCodec.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/BindingNormalizedCodecTest.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/BindingToNormalizedNodeCodecTest.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/AbstractDataBrokerTestCustomizer.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/Bug5524augmentUses.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/Bug5845booleanKeyTest.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/util/BindingBrokerTestFactory.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/util/BindingTestContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractGenerator.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractStreamWriterGenerator.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AugmentableDataNodeContainerEmitterSource.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataNodeContainerSerializerSource.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerGenerator.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerSource.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/StreamWriterGenerator.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/AbstractSource.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/StaticConstantDefinition.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingNormalizedNodeCodecRegistry.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamer.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamerBridge.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamerCustomizer.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/NodeCodecContext.java
binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AbstractBindingCodecTest.java
binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AugmentationClassDiscoveredAfterCodecTest.java
binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/ExceptionReportingTest.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/ClassCustomizer.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/ClassGenerator.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/CodeGenerationException.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/DefaultSourceCodeGenerator.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/FieldGenerator.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/JavassistUtils.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/NullSourceCodeGenerator.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/SourceCodeGenerator.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/SourceCodeGeneratorFactory.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/util/JavassistUtilsTest.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/util/SourceCodeGeneratorFactoryTest.java

index cfda3a31d73c6f73899ad9c1af55d0e9c97e9faa..5dcdaa9c2a6514426261112914da4136c1487d5d 100644 (file)
@@ -27,7 +27,6 @@ import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 import java.util.stream.Collectors;
-import javassist.ClassPool;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
@@ -36,12 +35,10 @@ import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeNode;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingLazyContainerNode;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.mdsal.binding.dom.codec.impl.MissingSchemaException;
 import org.opendaylight.mdsal.binding.generator.api.ClassLoadingStrategy;
 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
@@ -115,8 +112,7 @@ public class BindingToNormalizedNodeCodec implements BindingCodecTreeFactory,
 
     public static BindingToNormalizedNodeCodec newInstance(final ClassLoadingStrategy classLoadingStrategy,
             final DOMSchemaService schemaService) {
-        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(
-                StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())));
+        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry();
         BindingToNormalizedNodeCodec instance = new BindingToNormalizedNodeCodec(
                 classLoadingStrategy, codecRegistry, true);
         instance.listenerRegistration = schemaService.registerSchemaContextListener(instance);
index 9918660c531938a964a872a4183af9f99fb2fc90..afa6eb2151ca8c157aee1f0e9fb197b64d8f2abc 100644 (file)
@@ -25,14 +25,10 @@ import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
-import javassist.ClassPool;
 import org.junit.Test;
 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractSchemaAwareTest;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.DataObjectSerializerGenerator;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.bi.ba.rpcservice.rev140701.OpendaylightTestRpcServiceService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeLeafOnlyAugment;
@@ -70,9 +66,7 @@ public class BindingNormalizedCodecTest extends AbstractSchemaAwareTest {
     @Override
     protected void setupWithSchema(final SchemaContext schemaContext) {
         this.context = schemaContext;
-        final DataObjectSerializerGenerator streamWriter = StreamWriterGenerator.create(JavassistUtils.forClassPool(
-                    ClassPool.getDefault()));
-        final BindingNormalizedNodeCodecRegistry registry = new BindingNormalizedNodeCodecRegistry(streamWriter);
+        final BindingNormalizedNodeCodecRegistry registry = new BindingNormalizedNodeCodecRegistry();
         this.codec = new BindingToNormalizedNodeCodec(GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(),
                 registry, true);
     }
index 7a329690471e86d5244c801b59bd02e0bf8b1736..999c414c9ba79d73283a545044dd92aa441b4e10 100644 (file)
@@ -16,14 +16,10 @@ import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map.Entry;
-import javassist.ClassPool;
 import org.junit.Test;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.DataObjectSerializerGenerator;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -117,14 +113,10 @@ public class BindingToNormalizedNodeCodecTest {
 
     private static Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final NormalizedNode<?, ?> data,
             final SchemaContext schemaCtx) {
-        final DataObjectSerializerGenerator serializerGenerator =
-                StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault()));
-        final BindingNormalizedNodeCodecRegistry codecRegistry =
-                new BindingNormalizedNodeCodecRegistry(serializerGenerator);
         final GeneratedClassLoadingStrategy classLoadingStrategy =
                 GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
         final BindingRuntimeContext ctx = BindingRuntimeContext.create(classLoadingStrategy, schemaCtx);
-        codecRegistry.onBindingRuntimeContextUpdated(ctx);
+        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(ctx);
         final BindingToNormalizedNodeCodec codec =
                 new BindingToNormalizedNodeCodec(classLoadingStrategy, codecRegistry);
         final List<PathArgument> pathArgs = new ArrayList<>();
index 107178c61fe173856e1ea6132d138bb11feda1f7..f1a2b66ac10b36474168d2aba5a01209f4b52f9a 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.mdsal.binding.dom.adapter.test;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
-import javassist.ClassPool;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
 import org.opendaylight.mdsal.binding.api.NotificationService;
@@ -19,11 +18,8 @@ import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMNotificationPublishS
 import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMNotificationServiceAdapter;
 import org.opendaylight.mdsal.binding.dom.adapter.BindingToNormalizedNodeCodec;
 import org.opendaylight.mdsal.binding.dom.adapter.test.util.MockSchemaService;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.DataObjectSerializerGenerator;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
@@ -50,9 +46,7 @@ public abstract class AbstractDataBrokerTestCustomizer {
 
     public AbstractDataBrokerTestCustomizer() {
         this.schemaService = new MockSchemaService();
-        final ClassPool pool = ClassPool.getDefault();
-        final DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(pool));
-        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator);
+        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry();
         final GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
         this.bindingToNormalized = new BindingToNormalizedNodeCodec(loading, codecRegistry);
         this.schemaService.registerSchemaContextListener(this.bindingToNormalized);
index 25e6390ad43d40b5c79335a27535e0c06aef6298..942553a4f579e29824ff647ebb55b17437a95fa9 100644 (file)
@@ -10,16 +10,13 @@ package org.opendaylight.mdsal.binding.dom.adapter.test;
 import static org.junit.Assert.assertNotNull;
 
 import java.util.Collections;
-import javassist.ClassPool;
 import org.junit.Test;
 import org.opendaylight.mdsal.binding.dom.adapter.BindingToNormalizedNodeCodec;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.bug._5524.module1.rev160101.grouping.module1.ListModule11Builder;
 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.bug._5524.module1.rev160101.grouping.module1.list.module1._1.ListModule12Builder;
@@ -46,8 +43,7 @@ public class Bug5524augmentUses extends AbstractDataBrokerTest {
     @Test
     public void testBug5224() throws Exception {
         final BindingToNormalizedNodeCodec mappingService = new BindingToNormalizedNodeCodec(
-                GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), new BindingNormalizedNodeCodecRegistry(
-                        StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault()))));
+                GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), new BindingNormalizedNodeCodecRegistry());
         final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
         moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(Module4Main.class));
         mappingService.onGlobalContextUpdated(moduleInfoBackedContext.tryToCreateSchemaContext().get());
index 62cd86c64e521f414245e82eaedd605b0912c4ff..0f48b45693c4eaa8e917aa50162862805f867912 100644 (file)
@@ -10,16 +10,13 @@ package org.opendaylight.mdsal.binding.dom.adapter.test;
 import static org.junit.Assert.assertNotNull;
 
 import java.util.Collections;
-import javassist.ClassPool;
 import org.junit.Test;
 import org.opendaylight.mdsal.binding.dom.adapter.BindingToNormalizedNodeCodec;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.yang.gen.v1.urn.yang.foo.rev160101.BooleanContainer;
 import org.opendaylight.yang.gen.v1.urn.yang.foo.rev160101.BooleanContainerBuilder;
@@ -35,8 +32,7 @@ public class Bug5845booleanKeyTest extends AbstractDataBrokerTest {
     @Test
     public void testBug5845() throws Exception {
         final BindingToNormalizedNodeCodec mappingService = new BindingToNormalizedNodeCodec(
-                GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), new BindingNormalizedNodeCodecRegistry(
-                        StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault()))));
+                GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), new BindingNormalizedNodeCodecRegistry());
         final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
         moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(BooleanContainer.class));
         mappingService.onGlobalContextUpdated(moduleInfoBackedContext.tryToCreateSchemaContext().get());
index 7f9de19f2792e4b5460235e86ffbd23f4ec12ea9..e51bb5c6c4676ecae4d6f737f72c86daa900ebd9 100644 (file)
@@ -18,11 +18,11 @@ import javassist.ClassPool;
 public class BindingBrokerTestFactory {
 
     private static final ClassPool CLASS_POOL = ClassPool.getDefault();
+
     private boolean startWithParsedSchema = true;
     private ExecutorService executor;
     private ClassPool classPool;
 
-
     public boolean isStartWithParsedSchema() {
         return startWithParsedSchema;
     }
@@ -39,13 +39,13 @@ public class BindingBrokerTestFactory {
         this.executor = executor;
     }
 
-
     public BindingTestContext getTestContext() {
         Preconditions.checkState(executor != null, "Executor is not set.");
         ListeningExecutorService listenableExecutor = MoreExecutors.listeningDecorator(executor);
-        return new BindingTestContext(listenableExecutor, getClassPool(),startWithParsedSchema);
+        return new BindingTestContext(listenableExecutor, startWithParsedSchema);
     }
 
+    @Deprecated
     public ClassPool getClassPool() {
         if (classPool == null) {
             return CLASS_POOL;
@@ -54,8 +54,8 @@ public class BindingBrokerTestFactory {
         return classPool;
     }
 
+    @Deprecated
     public void setClassPool(final ClassPool classPool) {
         this.classPool = classPool;
     }
-
 }
index 710dd065c133bca3af22df7da5cc44721f89b5be..894e8b76d5d5f718da888d0a2d8081b580d6855c 100644 (file)
@@ -29,12 +29,9 @@ import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMNotificationServiceA
 import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMRpcProviderServiceAdapter;
 import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMRpcServiceAdapter;
 import org.opendaylight.mdsal.binding.dom.adapter.BindingToNormalizedNodeCodec;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.DataObjectSerializerGenerator;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
@@ -59,7 +56,6 @@ public class BindingTestContext implements AutoCloseable {
     private BindingToNormalizedNodeCodec codec;
 
     private final ListeningExecutorService executor;
-    private final ClassPool classPool;
 
     private final boolean startWithSchema;
 
@@ -96,10 +92,14 @@ public class BindingTestContext implements AutoCloseable {
         return codec;
     }
 
+    @Deprecated
     protected BindingTestContext(final ListeningExecutorService executor,
             final ClassPool classPool, final boolean startWithSchema) {
+        this(executor, startWithSchema);
+    }
+
+    protected BindingTestContext(final ListeningExecutorService executor, final boolean startWithSchema) {
         this.executor = executor;
-        this.classPool = classPool;
         this.startWithSchema = startWithSchema;
     }
 
@@ -146,11 +146,7 @@ public class BindingTestContext implements AutoCloseable {
     }
 
     public void startBindingToDomMappingService() {
-        checkState(classPool != null, "ClassPool needs to be present");
-
-        final DataObjectSerializerGenerator generator
-                = StreamWriterGenerator.create(JavassistUtils.forClassPool(classPool));
-        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator);
+        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry();
         final GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
         codec = new BindingToNormalizedNodeCodec(loading,  codecRegistry);
         mockSchemaService.registerSchemaContextListener(codec);
@@ -243,7 +239,7 @@ public class BindingTestContext implements AutoCloseable {
         return dataBroker;
     }
 
-    public void setSchemaModuleInfos(Set<YangModuleInfo> moduleInfos) {
+    public void setSchemaModuleInfos(final Set<YangModuleInfo> moduleInfos) {
         this.schemaModuleInfos = moduleInfos;
     }
 }
index f6f37d5518aa6ed5d09a403d808e5230f0db620e..cc38139c61027af255c55fd3f0841c78855e2070 100644 (file)
@@ -9,7 +9,10 @@ package org.opendaylight.mdsal.binding.dom.codec.gen.impl;
 
 /**
  * Package-private base class for sharing the loading capability.
+ *
+ * @deprecated This class is superseded by an internal implementation.
  */
+@Deprecated
 abstract class AbstractGenerator {
     /**
      * Ensure that the serializer class for specified class is loaded and return its name.
index 847260010d7e7dcf8cf76d3e6bd01e9a97da6745..d1c501f5a8ece023b3e122b9ebec7508c097c0b8 100644 (file)
@@ -46,6 +46,7 @@ import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Deprecated
 abstract class AbstractStreamWriterGenerator extends AbstractGenerator implements DataObjectSerializerGenerator {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractStreamWriterGenerator.class);
 
index 03bf419f0e6742a139811506baa7c1041bb2eff5..5e3bdd4fb4ee34d162103c7e9c61db029caf0c94 100644 (file)
@@ -11,6 +11,7 @@ import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 
+@Deprecated
 abstract class AugmentableDataNodeContainerEmitterSource extends DataNodeContainerSerializerSource {
     private static final String AUGMENTABLE_SERIALIZER = "AUGMENTABLE_SERIALIZER";
 
index 375fe00bd709cba2540843e09dc60c808f727799..e4261182e9fe0083aeb4db06b9eab286163bc5a3 100644 (file)
@@ -34,6 +34,7 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Deprecated
 abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSource {
 
     private static final Logger LOG = LoggerFactory.getLogger(DataNodeContainerSerializerSource.class);
index bbace44e966f6b687f6320785d0ec04bf19dc1e7..6cba594d266d8ea3ade5baf39b80ff6192c65d5e 100644 (file)
@@ -12,7 +12,10 @@ import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementatio
 
 /**
  * Public interface exposed from generator implementation.
+ *
+ * @deprecated This interface is superseded by an internal implementation.
  */
+@Deprecated
 public interface DataObjectSerializerGenerator {
     /**
      * Get a serializer for a particular type.
index a3cd64164481a0496af9a7817dbdea71fa60d49f..6b5149588935667fe78c539b55db898e0da6ccef 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
  * basis. During that time, the {@link #serialize(DataObjectSerializerRegistry, DataObject, BindingStreamEventWriter)}
  * method will be replaced by the real implementation.
  */
+@Deprecated
 final class DataObjectSerializerPrototype implements DataObjectSerializerImplementation {
     private static final DataObjectSerializerPrototype INSTANCE = new DataObjectSerializerPrototype();
 
index 25ba79b376681fbab58e3b8dd873ae353f7b6e28..818dfee89ebdbeb34788a1762b54069c9e17f613 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
 
+@Deprecated
 abstract class DataObjectSerializerSource extends AbstractSource {
 
     private static final ClassLoadingStrategy STRATEGY = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
index 779edc9b2a5649c861f90a377c543d778ba4d0d6..99022f36acc0fbabcfcbcbdaaa91bd1b7a612cb2 100644 (file)
@@ -30,7 +30,10 @@ import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
  * and Augmentable codecs are static properties of parent codec and stateless implementations are used
  * ({@link ChoiceDispatchSerializer}, {@link AugmentableDispatchSerializer}), which uses registry to dispatch to
  * concrete item codec.
+ *
+ * @deprecated This class is superseded by an internal implementation.
  */
+@Deprecated
 public final class StreamWriterGenerator extends AbstractStreamWriterGenerator {
     private static final String UNKNOWN_SIZE = BindingStreamEventWriter.class.getName() + ".UNKNOWN_SIZE";
 
index 64c6c500a401cb8c913ffb06ff632cf6fce5569b..75f44710153b7562568d7010206a9eb5360930e0 100644 (file)
@@ -15,7 +15,12 @@ import java.util.Iterator;
 import java.util.Set;
 import org.opendaylight.mdsal.binding.model.api.Type;
 
-// FIXME: 5.0.0: consider optimizing streaming use through returning StringBuilder from common methods
+/**
+ * An abstract source.
+ *
+ * @deprecated This class is superseded by an internal implementation.
+ */
+@Deprecated
 public abstract class AbstractSource {
     private final Set<StaticConstantDefinition> staticConstants = new HashSet<>();
 
index 743b852535b671ed409ff69f7ae40d146af12d94..b231a523dbdc6d21550d20db4fa13ad5093bf998 100644 (file)
@@ -19,7 +19,10 @@ import static java.util.Objects.requireNonNull;
  * <li>type - Java type for property</li>
  * <li>value - value to which property should be initialized</li>
  * </ul>
+ *
+ * @deprecated This class is superseded by an internal implementation.
  */
+@Deprecated
 public class StaticConstantDefinition {
 
     private final String name;
index 1078bda96496e8ac0d1f959c4d5bf2ebc76b0f1d..2c12aaa26cb2e207605d0aa19fba46f4aacb3061 100644 (file)
@@ -12,7 +12,12 @@ import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
@@ -25,6 +30,9 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import javassist.CannotCompileException;
+import javassist.NotFoundException;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
@@ -38,6 +46,7 @@ import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.binding.Action;
@@ -45,6 +54,7 @@ import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
 import org.opendaylight.yangtools.yang.binding.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Identifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -70,9 +80,48 @@ import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-final class BindingCodecContext implements CodecContextFactory, BindingCodecTree, Immutable {
+final class BindingCodecContext implements CodecContextFactory, BindingCodecTree, DataObjectSerializerRegistry,
+        Immutable {
+    private final class DataObjectSerializerProxy implements DataObjectSerializer, Delegator<DataObjectStreamer<?>> {
+        private final @NonNull DataObjectStreamer<?> delegate;
+
+        DataObjectSerializerProxy(final DataObjectStreamer<?> delegate) {
+            this.delegate = requireNonNull(delegate);
+        }
+
+        @Override
+        public DataObjectStreamer<?> getDelegate() {
+            return delegate;
+        }
+
+        @Override
+        public void serialize(final DataObject obj, final BindingStreamEventWriter stream) throws IOException {
+            delegate.serialize(BindingCodecContext.this, obj, stream);
+        }
+    }
+
     private static final Logger LOG = LoggerFactory.getLogger(BindingCodecContext.class);
 
+    private final LoadingCache<Class<?>, DataObjectStreamer<?>> streamers = CacheBuilder.newBuilder().build(
+        new CacheLoader<Class<?>, DataObjectStreamer<?>>() {
+            @Override
+            public DataObjectStreamer<?> load(final Class<?> key) throws CannotCompileException, IOException,
+                    NotFoundException, ReflectiveOperationException {
+                final Class<?> streamer = loader.generateSubclass(DataObjectStreamerCustomizer.CT_DOS, key, "streamer",
+                    DataObjectStreamerCustomizer.create(BindingCodecContext.this, key));
+
+                final Field instance = streamer.getDeclaredField(DataObjectStreamerCustomizer.INSTANCE_FIELD);
+                return (DataObjectStreamer<?>) instance.get(null);
+            }
+        });
+    private final LoadingCache<Class<?>, DataObjectSerializer> serializers = CacheBuilder.newBuilder().build(
+        new CacheLoader<Class<?>, DataObjectSerializer>() {
+            @Override
+            public DataObjectSerializer load(final Class<?> key) throws ExecutionException {
+                return new DataObjectSerializerProxy(streamers.get(key));
+            }
+        });
+
     private final @NonNull CodecClassLoader loader = StaticClassPool.createLoader();
     private final InstanceIdentifierCodec instanceIdentifierCodec;
     private final IdentityCodec identityCodec;
@@ -112,6 +161,16 @@ final class BindingCodecContext implements CodecContextFactory, BindingCodecTree
         return registry.getSerializer((Class) type);
     }
 
+    @Override
+    public DataObjectStreamer<?> getDataObjectSerializer(final Class<?> type) {
+        return streamers.getUnchecked(type);
+    }
+
+    @Override
+    public DataObjectSerializer getSerializer(final Class<? extends DataObject> type) {
+        return serializers.getUnchecked(type);
+    }
+
     public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriter(final InstanceIdentifier<?> path,
             final NormalizedNodeStreamWriter domWriter) {
         final List<YangInstanceIdentifier.PathArgument> yangArgs = new LinkedList<>();
index 3a9452922341d3a3ae832c9bedd921761c0d9cbd..6952efa8eea14bf613e68abfbaa984dd188198e0 100644 (file)
@@ -7,11 +7,9 @@
  */
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
+import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.IOException;
 import java.util.AbstractMap.SimpleEntry;
@@ -19,8 +17,10 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import java.util.function.BiFunction;
 import java.util.function.Function;
+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
@@ -33,13 +33,11 @@ import org.opendaylight.mdsal.binding.dom.codec.util.AbstractBindingLazyContaine
 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
-import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.yang.binding.Action;
 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
-import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
@@ -65,22 +63,33 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerRegistry,
-        BindingCodecTreeFactory, BindingNormalizedNodeWriterFactory,
-        BindingNormalizedNodeSerializer {
+        BindingCodecTreeFactory, BindingNormalizedNodeWriterFactory, BindingNormalizedNodeSerializer {
     private static final Logger LOG = LoggerFactory.getLogger(BindingNormalizedNodeCodecRegistry.class);
 
     private final DataObjectSerializerGenerator generator;
-    private final LoadingCache<Class<? extends DataObject>, DataObjectSerializer> serializers;
+
+    private static final AtomicReferenceFieldUpdater<BindingNormalizedNodeCodecRegistry, BindingCodecContext> UPDATER =
+            AtomicReferenceFieldUpdater.newUpdater(BindingNormalizedNodeCodecRegistry.class, BindingCodecContext.class,
+                "codecContext");
     private volatile BindingCodecContext codecContext;
 
+    public BindingNormalizedNodeCodecRegistry() {
+        this.generator = null;
+    }
+
+    public BindingNormalizedNodeCodecRegistry(final BindingRuntimeContext codecContext) {
+        this();
+        onBindingRuntimeContextUpdated(codecContext);
+    }
+
+    @Deprecated
     public BindingNormalizedNodeCodecRegistry(final DataObjectSerializerGenerator generator) {
         this.generator = requireNonNull(generator);
-        this.serializers = CacheBuilder.newBuilder().weakKeys().build(new GeneratorLoader());
     }
 
     @Override
     public DataObjectSerializer getSerializer(final Class<? extends DataObject> type) {
-        return serializers.getUnchecked(type);
+        return codecContext().getSerializer(type);
     }
 
     public BindingCodecTree getCodecContext() {
@@ -88,8 +97,28 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
     }
 
     public void onBindingRuntimeContextUpdated(final BindingRuntimeContext context) {
-        codecContext = new BindingCodecContext(context, this);
-        generator.onBindingRuntimeContextUpdated(context);
+        // BindingCodecContext is a costly resource. Let us not ditch it unless we have to
+        final BindingCodecContext current = codecContext;
+        if (current != null && context.equals(current.getRuntimeContext())) {
+            LOG.debug("Skipping update of runtime context {}", context);
+            return;
+        }
+
+        final BindingCodecContext updated = new BindingCodecContext(context, this);
+        if (UPDATER.compareAndSet(this, current, updated)) {
+            if (generator != null) {
+                generator.onBindingRuntimeContextUpdated(context);
+            }
+        } else {
+            LOG.warn("Concurrent update of runtime context (expected={} current={}) detected at ", current,
+                codecContext, new Throwable());
+        }
+    }
+
+    final @NonNull BindingCodecContext codecContext() {
+        final BindingCodecContext local = codecContext;
+        checkState(local != null, "No context available yet");
+        return local;
     }
 
     @Override
@@ -328,33 +357,6 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         }
     }
 
-    private final class GeneratorLoader extends CacheLoader<Class<? extends DataContainer>, DataObjectSerializer> {
-        @Override
-        public DataObjectSerializer load(final Class<? extends DataContainer> key) {
-            final DataObjectSerializerImplementation prototype = generator.getSerializer(key);
-            return new DataObjectSerializerProxy(prototype);
-        }
-    }
-
-    private final class DataObjectSerializerProxy
-            implements DataObjectSerializer, Delegator<DataObjectSerializerImplementation> {
-        private final DataObjectSerializerImplementation delegate;
-
-        DataObjectSerializerProxy(final DataObjectSerializerImplementation delegate) {
-            this.delegate = delegate;
-        }
-
-        @Override
-        public DataObjectSerializerImplementation getDelegate() {
-            return delegate;
-        }
-
-        @Override
-        public void serialize(final DataObject obj, final BindingStreamEventWriter stream) throws IOException {
-            delegate.serialize(BindingNormalizedNodeCodecRegistry.this, obj, stream);
-        }
-    }
-
     @NonNullByDefault
     private abstract static class AbstractLazyActionContainerNode<T extends DataObject>
             extends AbstractBindingLazyContainerNode<T, BindingNormalizedNodeCodecRegistry> {
diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamer.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamer.java
new file mode 100644 (file)
index 0000000..f48ade1
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.mdsal.binding.dom.codec.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.mdsal.binding.dom.codec.util.AugmentationReader;
+import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BindingSerializer;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base superclass for all concrete streamers, that is objects which are able to turn a concrete DataObject into a
+ * stream of events.
+ *
+ * @param <T> DataObject type
+ */
+@Beta
+public abstract class DataObjectStreamer<T extends DataObject> implements DataObjectSerializerImplementation {
+    private static final Logger LOG = LoggerFactory.getLogger(DataObjectStreamer.class);
+
+    protected DataObjectStreamer() {
+
+    }
+
+    protected static final void streamAnyxml(final BindingStreamEventWriter writer, final String localName,
+            final Object value) throws IOException {
+        if (value != null) {
+            writer.anyxmlNode(localName, value);
+        }
+    }
+
+    protected static final void streamAugmentations(final DataObjectSerializerRegistry registry,
+            final BindingStreamEventWriter writer, final Augmentable<?> obj) throws IOException {
+        final Map<Class<? extends Augmentation<?>>, Augmentation<?>> augmentations;
+        if (registry instanceof AugmentationReader) {
+            augmentations = ((AugmentationReader) registry).getAugmentations(obj);
+        } else if (Proxy.isProxyClass(obj.getClass())) {
+            augmentations = getFromProxy(obj);
+        } else {
+            augmentations = BindingReflections.getAugmentations(obj);
+        }
+        for (final Entry<Class<? extends Augmentation<?>>, Augmentation<?>> aug : augmentations.entrySet()) {
+            emitAugmentation(aug.getKey(), aug.getValue(), writer, registry);
+        }
+    }
+
+    private static Map<Class<? extends Augmentation<?>>, Augmentation<?>> getFromProxy(final Augmentable<?> obj) {
+        final InvocationHandler proxy = Proxy.getInvocationHandler(obj);
+        if (proxy instanceof AugmentationReader) {
+            return ((AugmentationReader) proxy).getAugmentations(obj);
+        }
+        return ImmutableClassToInstanceMap.of();
+    }
+
+    protected static final <C extends DataContainer> void streamChoice(final Class<C> choiceClass,
+            final DataObjectSerializerRegistry registry, final BindingStreamEventWriter writer, final C value)
+                    throws IOException {
+        if (value != null) {
+            final Class<? extends DataContainer> caseClass = value.implementedInterface();
+            writer.startChoiceNode(choiceClass, BindingStreamEventWriter.UNKNOWN_SIZE);
+            final DataObjectSerializer caseStreamer = registry.getSerializer(caseClass.asSubclass(DataObject.class));
+            if (caseStreamer != null && tryCache(writer, (DataObject) value)) {
+                caseStreamer.serialize((DataObject) value, writer);
+            } else {
+                LOG.warn("No serializer for case {} is available in registry {}", caseClass, registry);
+            }
+
+            writer.endNode();
+        }
+    }
+
+    protected static final <C extends DataObject> void streamContainer(final DataObjectStreamer<C> childStreamer,
+            final DataObjectSerializerRegistry registry, final BindingStreamEventWriter writer, final C value)
+                    throws IOException {
+        if (value != null && tryCache(writer, value)) {
+            childStreamer.serialize(registry, value, writer);
+        }
+    }
+
+    protected static final void streamLeaf(final BindingStreamEventWriter writer, final String localName,
+            final Object value) throws IOException {
+        if (value != null) {
+            writer.leafNode(localName, value);
+        }
+    }
+
+    protected static final void streamLeafList(final BindingStreamEventWriter writer, final String localName,
+            final List<?> value) throws IOException {
+        if (value != null) {
+            writer.startLeafSet(localName, value.size());
+            commonStreamLeafset(writer, value);
+        }
+    }
+
+    protected static final void streamOrderedLeafList(final BindingStreamEventWriter writer,
+            final String localName, final List<?> value) throws IOException {
+        if (value != null) {
+            writer.startOrderedLeafSet(localName, value.size());
+            commonStreamLeafset(writer, value);
+        }
+    }
+
+    protected static final <E extends DataObject> void streamList(final Class<E> childClass,
+            final DataObjectStreamer<E> childStreamer, final DataObjectSerializerRegistry registry,
+            final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
+        if (value != null) {
+            writer.startUnkeyedList(childClass, value.size());
+            commonStreamList(registry, writer, childStreamer, value);
+        }
+    }
+
+    protected static final <E extends DataObject & Identifiable<?>> void streamMap(final Class<E> childClass,
+            final DataObjectStreamer<E> childStreamer, final DataObjectSerializerRegistry registry,
+            final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
+        if (value != null) {
+            writer.startMapNode(childClass, value.size());
+            commonStreamList(registry, writer, childStreamer, value);
+        }
+    }
+
+    protected static final <E extends DataObject & Identifiable<?>> void streamOrderedMap(final Class<E> childClass,
+            final DataObjectStreamer<E> childStreamer, final DataObjectSerializerRegistry registry,
+            final BindingStreamEventWriter writer, final List<? extends E> value) throws IOException {
+        if (value != null) {
+            writer.startOrderedMapNode(childClass, value.size());
+            commonStreamList(registry, writer, childStreamer, value);
+        }
+    }
+
+    private static <E extends DataObject> void commonStreamList(final DataObjectSerializerRegistry registry,
+            final BindingStreamEventWriter writer, final DataObjectStreamer<E> childStreamer,
+            final Collection<? extends E> value) throws IOException {
+
+        for (E entry : value) {
+            if (tryCache(writer, entry)) {
+                childStreamer.serialize(registry, entry, writer);
+            }
+        }
+        writer.endNode();
+    }
+
+
+    private static void commonStreamLeafset(final BindingStreamEventWriter writer, final List<?> value)
+            throws IOException {
+        for (Object entry : value) {
+            writer.leafSetEntryNode(entry);
+        }
+        writer.endNode();
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static void emitAugmentation(final Class type, final Augmentation<?> value,
+            final BindingStreamEventWriter writer, final DataObjectSerializerRegistry registry) throws IOException {
+        /*
+         * Binding Specification allowed to insert augmentation with null for
+         * value, which effectively could be used to remove augmentation
+         * from builder / DTO.
+         */
+        if (value != null) {
+            checkArgument(value instanceof DataObject);
+            @SuppressWarnings("unchecked")
+            final DataObjectSerializer serializer = registry.getSerializer(type);
+            if (serializer != null) {
+                serializer.serialize((DataObject) value, writer);
+            } else {
+                LOG.warn("DataObjectSerializer is not present for {} in registry {}", type, registry);
+            }
+        }
+    }
+
+    private static boolean tryCache(final BindingStreamEventWriter writer, final DataObject value) {
+        return writer instanceof BindingSerializer ? ((BindingSerializer) writer).serialize(value) == null : true;
+    }
+}
diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamerBridge.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamerBridge.java
new file mode 100644 (file)
index 0000000..e75ee77
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.mdsal.binding.dom.codec.impl;
+
+import static com.google.common.base.Verify.verifyNotNull;
+
+import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Bridge for initializing {@link DataObjectStreamer} instance constants during class loading time. This class is public
+ * only due to implementation restrictions and can change at any time.
+ */
+// FIXME: this bridge is only necessary to work around Javassist compiler resolution of dependencies. If we switch to
+//         a more bytecode-oriented framework, this bridge becomes superfluous.
+//
+@Beta
+public final class DataObjectStreamerBridge {
+    private static final ThreadLocal<DataObjectStreamerCustomizer> CURRENT_CUSTOMIZER = new ThreadLocal<>();
+
+    private DataObjectStreamerBridge() {
+
+    }
+
+    public static @NonNull DataObjectStreamer<?> resolve(final @NonNull String methodName) {
+        return verifyNotNull(CURRENT_CUSTOMIZER.get(), "No customizer attached").resolve(methodName);
+    }
+
+    static @Nullable DataObjectStreamerCustomizer setup(final @NonNull DataObjectStreamerCustomizer next) {
+        final DataObjectStreamerCustomizer prev = CURRENT_CUSTOMIZER.get();
+        CURRENT_CUSTOMIZER.set(verifyNotNull(next));
+        return prev;
+    }
+
+    static void tearDown(final @Nullable DataObjectStreamerCustomizer prev) {
+        if (prev == null) {
+            CURRENT_CUSTOMIZER.remove();
+        } else {
+            CURRENT_CUSTOMIZER.set(prev);
+        }
+    }
+}
diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamerCustomizer.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamerCustomizer.java
new file mode 100644 (file)
index 0000000..f958c15
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.mdsal.binding.dom.codec.impl;
+
+import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.Modifier;
+import javassist.NotFoundException;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.dom.codec.impl.NodeCodecContext.CodecContextFactory;
+import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader;
+import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader.Customizer;
+import org.opendaylight.mdsal.binding.dom.codec.loader.StaticClassPool;
+import org.opendaylight.mdsal.binding.dom.codec.util.BindingSchemaMapping;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.MethodSignature;
+import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
+import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Beta
+public final class DataObjectStreamerCustomizer implements Customizer {
+    static final CtClass CT_DOS = StaticClassPool.findClass(DataObjectStreamer.class);
+    static final String INSTANCE_FIELD = "INSTANCE";
+
+    private static final Logger LOG = LoggerFactory.getLogger(DataObjectStreamerCustomizer.class);
+    private static final String UNKNOWN_SIZE = BindingStreamEventWriter.class.getName() + ".UNKNOWN_SIZE";
+
+    private static final CtClass CT_VOID = StaticClassPool.findClass(void.class);
+    private static final CtClass[] SERIALIZE_ARGS = new CtClass[] {
+        StaticClassPool.findClass(DataObjectSerializerRegistry.class),
+        StaticClassPool.findClass(DataObject.class),
+        StaticClassPool.findClass(BindingStreamEventWriter.class)
+    };
+
+    private final Map<String, Class<? extends DataObject>> constants = new HashMap<>();
+    private final ImmutableMap<String, Type> props;
+    private final CodecContextFactory registry;
+    private final DataNodeContainer schema;
+    private final String startEvent;
+    private final Class<?> type;
+
+    DataObjectStreamerCustomizer(final CodecContextFactory registry, final GeneratedType genType,
+            final DataNodeContainer schema, final Class<?> type, final String startEvent) {
+        this.registry = requireNonNull(registry);
+        this.schema = requireNonNull(schema);
+        this.type = requireNonNull(type);
+        this.startEvent = requireNonNull(startEvent);
+        props = collectAllProperties(genType);
+    }
+
+    public static DataObjectStreamerCustomizer create(final CodecContextFactory registry, final Class<?> type) {
+        final Entry<GeneratedType, WithStatus> typeAndSchema = registry.getRuntimeContext().getTypeWithSchema(type);
+        final WithStatus schema = typeAndSchema.getValue();
+
+        final String startEvent;
+        if (schema instanceof ContainerSchemaNode || schema instanceof NotificationDefinition) {
+            startEvent = "startContainerNode(" + type.getName() + ".class," + UNKNOWN_SIZE;
+        } else if (schema instanceof ListSchemaNode) {
+            final ListSchemaNode casted = (ListSchemaNode) schema;
+            if (!casted.getKeyDefinition().isEmpty()) {
+                startEvent = "startMapEntryNode(obj." + BindingMapping.IDENTIFIABLE_KEY_NAME + "(), " + UNKNOWN_SIZE;
+            } else {
+                startEvent = "startUnkeyedListItem(" + UNKNOWN_SIZE;
+            }
+        } else if (schema instanceof AugmentationSchemaNode) {
+            startEvent = "startAugmentationNode(" + type.getName() + ".class";
+        } else if (schema instanceof CaseSchemaNode) {
+            startEvent = "startCase(" + type.getName() + ".class, " + UNKNOWN_SIZE;
+        } else {
+            throw new UnsupportedOperationException("Schema type " + schema.getClass() + " is not supported");
+        }
+
+        return new DataObjectStreamerCustomizer(registry, typeAndSchema.getKey(), (DataNodeContainer) schema, type,
+            startEvent);
+    }
+
+    @Override
+    public List<Class<?>> customize(final CodecClassLoader loader, final CtClass bindingClass, final CtClass generated)
+            throws CannotCompileException, NotFoundException, IOException {
+        LOG.trace("Definining streamer {}", generated.getName());
+
+        final CtField instanceField = new CtField(generated, INSTANCE_FIELD, generated);
+        instanceField.setModifiers(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
+        generated.addField(instanceField, "new " + generated.getName() + "()");
+
+        // This results in a body
+        final String objType = bindingClass.getName();
+        final StringBuilder sb = new StringBuilder()
+                .append("{\n")
+                .append("final ").append(objType).append(" obj = (").append(objType).append(") $2;\n")
+                .append("$3.").append(startEvent).append(");\n");
+
+        final List<Class<?>> dependencies = emitChildren(sb, loader, generated);
+        if (Augmentable.class.isAssignableFrom(type)) {
+            sb.append("streamAugmentations($1, $3, obj);\n");
+        }
+
+        sb.append("$3.endNode();\n")
+            .append('}');
+
+        final CtMethod serialize = new CtMethod(CT_VOID, "serialize", SERIALIZE_ARGS, generated);
+        serialize.setModifiers(Modifier.PUBLIC);
+        serialize.setBody(sb.toString());
+        generated.addMethod(serialize);
+
+        generated.setModifiers(Modifier.PUBLIC | Modifier.FINAL);
+        LOG.trace("Definition of {} done", generated.getName());
+
+        return dependencies;
+    }
+
+    @Override
+    public Class<?> customizeLoading(final @NonNull Supplier<Class<?>> loader) {
+        if (constants.isEmpty()) {
+            return loader.get();
+        }
+
+        final DataObjectStreamerCustomizer prev = DataObjectStreamerBridge.setup(this);
+        try {
+            final Class<?> result = loader.get();
+
+            /*
+             * This a bit of magic to support DataObjectStreamer constants. These constants need to be resolved while
+             * we have the information needed to find them -- that information is being held in this instance and we
+             * leak it to a thread-local variable held by DataObjectStreamerBridge.
+             *
+             * By default the JVM will defer class initialization to first use, which unfortunately is too late for
+             * us, and hence we need to force class to initialize.
+             */
+            try {
+                Class.forName(result.getName(), true, result.getClassLoader());
+            } catch (ClassNotFoundException e) {
+                throw new LinkageError("Failed to find newly-defined " + result, e);
+            }
+
+            return result;
+        } finally {
+            DataObjectStreamerBridge.tearDown(prev);
+        }
+    }
+
+    @NonNull DataObjectStreamer<?> resolve(final @NonNull String methodName) {
+        final Class<? extends DataObject> target = verifyNotNull(constants.get(methodName), "Cannot resolve type of %s",
+            methodName);
+        return verifyNotNull(registry.getDataObjectSerializer(target), "Cannot find serializer for %s", target);
+    }
+
+    private List<Class<?>> emitChildren(final StringBuilder sb, final CodecClassLoader loader,
+            final CtClass generated) throws CannotCompileException {
+        final List<Class<?>> dependencies = new ArrayList<>();
+
+        for (final DataSchemaNode schemaChild : schema.getChildNodes()) {
+            if (!schemaChild.isAugmenting()) {
+                final String getterName = BindingSchemaMapping.getGetterMethodName(schemaChild);
+                final Method getter;
+                try {
+                    getter = type.getMethod(getterName);
+                } catch (NoSuchMethodException e) {
+                    throw new IllegalStateException("Failed to find getter " + getterName, e);
+                }
+
+                final Class<?> dependency = emitChild(sb, loader, generated, getterName, getter.getReturnType(),
+                    schemaChild);
+                if (dependency != null) {
+                    LOG.trace("Require dependency {}", dependency);
+                    dependencies.add(dependency);
+                }
+            }
+        }
+
+        return dependencies;
+    }
+
+    private @Nullable Class<?> emitChild(final StringBuilder sb, final CodecClassLoader loader, final CtClass generated,
+            final String getterName, final Class<?> returnType, final DataSchemaNode child)
+                    throws CannotCompileException {
+        if (child instanceof LeafSchemaNode) {
+            sb.append("streamLeaf($3, \"").append(child.getQName().getLocalName()).append("\", obj.")
+            .append(getterName).append("());\n");
+            return null;
+        }
+        if (child instanceof ContainerSchemaNode) {
+            final Class<? extends DataObject> itemClass = returnType.asSubclass(DataObject.class);
+            final String constField = declareDependency(generated, getterName, itemClass);
+
+            sb.append("streamContainer(").append(constField).append(", $1, $3, obj.").append(getterName)
+            .append("());\n");
+            return registry.getDataObjectSerializer(itemClass).getClass();
+        }
+        if (child instanceof ListSchemaNode) {
+            final Type childType = props.get(getterName);
+            verify(childType instanceof ParameterizedType, "Unexpected type %s for %s", childType, getterName);
+            final Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
+            final Class<?> valueClass;
+            try {
+                valueClass = loader.loadClass(valueType.getFullyQualifiedName());
+            } catch (ClassNotFoundException e) {
+                throw new LinkageError("Failed to load " + valueType, e);
+            }
+
+            verify(DataObject.class.isAssignableFrom(valueClass), "Value type %s of %s is not a DataObject", valueClass,
+                returnType);
+            final Class<? extends DataObject> itemClass = valueClass.asSubclass(DataObject.class);
+            final ListSchemaNode casted = (ListSchemaNode) child;
+
+            sb.append("stream");
+            if (casted.getKeyDefinition().isEmpty()) {
+                sb.append("List");
+            } else {
+                if (casted.isUserOrdered()) {
+                    sb.append("Ordered");
+                }
+                sb.append("Map");
+            }
+
+            final String constField = declareDependency(generated, getterName, itemClass);
+            sb.append('(').append(valueClass.getName()).append(".class, ").append(constField).append(", $1, $3, obj.")
+            .append(getterName).append("());\n");
+            return registry.getDataObjectSerializer(itemClass).getClass();
+        }
+        if (child instanceof AnyXmlSchemaNode) {
+            sb.append("streamAnyxml($3, \"").append(child.getQName().getLocalName()).append("\", obj.")
+            .append(getterName).append("());\n");
+            return null;
+        }
+        if (child instanceof LeafListSchemaNode) {
+            sb.append("stream");
+            if (((LeafListSchemaNode) child).isUserOrdered()) {
+                sb.append("Ordered");
+            }
+            sb.append("LeafList($3, \"").append(child.getQName().getLocalName()).append("\", obj.")
+            .append(getterName).append("());\n");
+            return null;
+        }
+        if (child instanceof ChoiceSchemaNode) {
+            sb.append("streamChoice(").append(returnType.getName()).append(".class, $1, $3, obj.").append(getterName)
+            .append("());\n");
+            return null;
+        }
+
+        LOG.debug("Ignoring {} due to unhandled schema {}", getterName, child);
+        return null;
+    }
+
+    /*
+     * Javassist not quite helpful in our environment. We really want to output plain bytecode so that it links
+     * using normal ClassLoader mechanics (supported via CodecClassLoader), but Javassist's compiler really gets in
+     * the way of keeping things simple by requiring CtClass references to dependencies at the the time we set the
+     * implementation body. In order to side-step those requirements, we rely on defining references to our dependencies
+     * as constants and fill them up via customizeLoading().
+     *
+     * This method defines the constants for later use. Should we migrate to a more byte-code oriented framework
+     * (like ByteBuddy), we will pay some cost in assembling the method bodies, we can ditch the constants, as we
+     * provide INSTANCE_FIELD which can readily be reused and CodecClassLoader will resolve the dependencies without
+     * any problems.
+     */
+    private String declareDependency(final CtClass generated, final String getterName,
+            final Class<? extends DataObject> bindingClass) throws CannotCompileException {
+        final String fieldName = getterName + "_STREAMER";
+
+        final CtField instanceField = new CtField(CT_DOS, fieldName, generated);
+        instanceField.setModifiers(Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL);
+        generated.addField(instanceField,
+            DataObjectStreamerBridge.class.getName() + ".resolve(\"" + getterName + "\")");
+
+        verify(constants.put(getterName, bindingClass) == null, "Duplicate dependency for %s", getterName);
+        return fieldName;
+    }
+
+    private static ImmutableMap<String, Type> collectAllProperties(final GeneratedType type) {
+        final Map<String, Type> props = new HashMap<>();
+        collectAllProperties(type, props);
+        return ImmutableMap.copyOf(props);
+    }
+
+    private static void collectAllProperties(final GeneratedType type, final Map<String, Type> hashMap) {
+        for (final MethodSignature definition : type.getMethodDefinitions()) {
+            hashMap.put(definition.getName(), definition.getReturnType());
+        }
+        for (final Type parent : type.getImplements()) {
+            if (parent instanceof GeneratedType) {
+                collectAllProperties((GeneratedType) parent, hashMap);
+            }
+        }
+    }
+}
index 5944d7951e26468fa110efa6b81be3746a04ab4a..95f308fe61854ed31ba64166e7a4e545e99c9c18 100644 (file)
@@ -83,6 +83,8 @@ abstract class NodeCodecContext implements BindingCodecTreeNode {
          */
         @NonNull CodecClassLoader getLoader();
 
+        @NonNull DataObjectStreamer<?> getDataObjectSerializer(Class<?> type);
+
         DataObjectSerializer getEventStreamSerializer(Class<?> type);
     }
 
index 766523b8e29fee19898cf9d729a2f5fc4c5745ff..6176aa06d9838865d8796adb4ad28442ae5bfdef 100644 (file)
@@ -7,34 +7,26 @@
  */
 package org.opendaylight.mdsal.binding.dom.codec.test;
 
-import javassist.ClassPool;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 
 public abstract class AbstractBindingCodecTest extends AbstractBindingRuntimeTest {
-    private static JavassistUtils UTILS;
-
     protected BindingNormalizedNodeCodecRegistry registry;
 
     @BeforeClass
     public static void beforeClass() {
         AbstractBindingRuntimeTest.beforeClass();
-        UTILS = JavassistUtils.forClassPool(ClassPool.getDefault());
     }
 
     @AfterClass
     public static void afterClass() {
-        UTILS = null;
         AbstractBindingRuntimeTest.afterClass();
     }
 
     @Before
     public void before() {
-        this.registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(UTILS));
-        this.registry.onBindingRuntimeContextUpdated(getRuntimeContext());
+        this.registry = new BindingNormalizedNodeCodecRegistry(getRuntimeContext());
     }
 }
index 61528083578d736b0c70f3cb464703454be095d8..297d59ae7cf2ff613cf20cb75e05582b5a14cacd 100644 (file)
@@ -13,16 +13,13 @@ import static org.junit.Assert.assertNotNull;
 import java.util.HashSet;
 import java.util.Map.Entry;
 import java.util.Set;
-import javassist.ClassPool;
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.mdsal.binding.dom.codec.impl.MissingClassInLoadingStrategyException;
 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeLeafOnlyAugment;
@@ -57,9 +54,7 @@ public class AugmentationClassDiscoveredAfterCodecTest {
         mockedContext = new ClassExcludingClassLoadingStrategy(ctx);
         schemaContext = ctx.tryToCreateSchemaContext().get();
         runtimeContext = BindingRuntimeContext.create(mockedContext, schemaContext);
-        final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
-        registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
-        registry.onBindingRuntimeContextUpdated(runtimeContext);
+        registry = new BindingNormalizedNodeCodecRegistry(runtimeContext);
     }
 
     private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
index eaa748b8e56b3cf511b40b34f2dac1a84b388ede..f1be7157d49c15160fd25627f1b7a0765db57642 100644 (file)
@@ -7,16 +7,13 @@
  */
 package org.opendaylight.mdsal.binding.dom.codec.test;
 
-import javassist.ClassPool;
 import org.junit.Test;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.mdsal.binding.dom.codec.impl.IncorrectNestingException;
 import org.opendaylight.mdsal.binding.dom.codec.impl.MissingSchemaException;
 import org.opendaylight.mdsal.binding.dom.codec.impl.MissingSchemaForClassException;
 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeLeafOnlyAugment;
@@ -94,10 +91,7 @@ public class ExceptionReportingTest {
         }
         final SchemaContext schema = ctx.tryToCreateSchemaContext().get();
         final BindingRuntimeContext runtimeCtx = BindingRuntimeContext.create(ctx, schema);
-        final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
-        final BindingNormalizedNodeCodecRegistry registry = new BindingNormalizedNodeCodecRegistry(
-            StreamWriterGenerator.create(utils));
-        registry.onBindingRuntimeContextUpdated(runtimeCtx);
+        final BindingNormalizedNodeCodecRegistry registry = new BindingNormalizedNodeCodecRegistry(runtimeCtx);
         return registry;
     }
 }
index 20a6e4af711c392c60e571e46670979ed5341dd2..62c7ce5b71ff79042e796c27cb616bbfe47254d3 100644 (file)
@@ -14,8 +14,11 @@ import javassist.NotFoundException;
 
 /**
  * Interface allowing customization of classes after loading.
+ *
+ * @deprecated Code generation is a concert separate from type mapping and is an implementation detail.
  */
 @Beta
+@Deprecated
 @FunctionalInterface
 public interface ClassCustomizer {
     /**
index 8cd7e7c86c9ecf239936cca6c4d941db76f53e31..56728cd03c3149bbf8b26762a9acf70d54b11fca 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.mdsal.binding.generator.util;
 import javassist.CannotCompileException;
 import javassist.CtClass;
 
+@Deprecated
 public interface ClassGenerator {
     void process(CtClass cls) throws CannotCompileException;
 }
index a115b953d4a718dd7567ec7d106695dd3de43b22..a5f37cc6922f55ed5ddb7894e6629037fc077ed0 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.mdsal.binding.generator.util;
 
+@Deprecated
 public class CodeGenerationException extends RuntimeException {
     private static final long serialVersionUID = 1L;
 
index d3c3a7f4e577b8d918036e8ce3c1e36c59ede947..ce44f64c5be51d618f7701a17d66b1cf58fb404f 100644 (file)
@@ -5,7 +5,6 @@
  * 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.mdsal.binding.generator.util;
 
 import com.google.common.io.Files;
@@ -29,7 +28,10 @@ import org.slf4j.LoggerFactory;
  * written to a file under a specified directory.
  *
  * @author Thomas Pantelis
+ *
+ * @deprecated Code generation is a concert separate from type mapping and is an implementation detail.
  */
+@Deprecated
 public class DefaultSourceCodeGenerator implements SourceCodeGenerator {
     private static final Logger LOG = LoggerFactory.getLogger(DefaultSourceCodeGenerator.class);
 
index 297f69887fb5dac198e146f94500a241277f4c3b..3b8b7e840b370f5b234301cf21b5edac0e0eca0e 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.mdsal.binding.generator.util;
 
 import javassist.CtField;
 
+@Deprecated
 public interface FieldGenerator {
     void process(CtField field);
 }
index dae125c5470a7bb692a26b700a95f50d33a6cae3..74ee3e14f0d2150ed876d196f5278f83379fe967 100644 (file)
@@ -27,7 +27,11 @@ import org.slf4j.LoggerFactory;
 /**
  * Users of this utility class are expected to synchronize on this instance it they need to ensure atomic operations
  * on it. Individual operations are synchronized and therefore are thread-safe.
+ *
+ * @deprecated This class has been deprecated due to not being quite able to work in multi-classloader environments
+ *             without holding strong central references.
  */
+@Deprecated
 @NonNullByDefault
 public final class JavassistUtils {
     private static final Logger LOG = LoggerFactory.getLogger(JavassistUtils.class);
index 3d8ba583dbea388d4c43bec7dd794d247b16395c..de654b2b1cd719c0e1e64d172ecad04e0c9d1568 100644 (file)
@@ -5,7 +5,6 @@
  * 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.mdsal.binding.generator.util;
 
 import javassist.CtClass;
@@ -17,17 +16,18 @@ import javassist.CtMethod;
  *
  * @author Thomas Pantelis
  */
+@Deprecated
 public class NullSourceCodeGenerator implements SourceCodeGenerator {
 
     @Override
-    public void appendField(CtField field, String value) {
+    public void appendField(final CtField field, final String value) {
     }
 
     @Override
-    public void appendMethod(CtMethod method, String code) {
+    public void appendMethod(final CtMethod method, final String code) {
     }
 
     @Override
-    public void outputGeneratedSource(CtClass ctClass) {
+    public void outputGeneratedSource(final CtClass ctClass) {
     }
 }
index 7f071a9b0ebfc400ad63a6dc80b6b30a541b4654..c208095b30fe7cea0539739a528d5dc51c09f36b 100644 (file)
@@ -5,7 +5,6 @@
  * 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.mdsal.binding.generator.util;
 
 import javassist.CtClass;
@@ -18,7 +17,10 @@ import javassist.CtMethod;
  * is called, the entire class source code is generated and outputted.
  *
  * @author Thomas Pantelis
+ * @deprecated Code generation is a concert separate from type mapping and is an implementation detail. Most notably
+ *             there may actually not be intermediate source code.
  */
+@Deprecated
 public interface SourceCodeGenerator {
 
     /**
index d26006e882c3172e06b37b7c86d18b9b78d9bc8f..e2566a722786cc9cca0896b06de1d2d577708aa9 100644 (file)
@@ -5,14 +5,15 @@
  * 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.mdsal.binding.generator.util;
 
 /**
  * Factory class for creating SourceCodeGenerator instances.
  *
  * @author Thomas Pantelis
+ * @deprecated Code generation is a concert separate from type mapping and is an implementation detail.
  */
+@Deprecated
 public class SourceCodeGeneratorFactory {
 
     private static final String GENERATE_CODEC_SOURCE_PROP = "org.opendaylight.yangtools.sal.generateCodecSource";
index 929187ef6c8a4b14aa5218bd37227272eb283603..ac464341c0540f503c31219cc96e68949b0e2585 100644 (file)
@@ -27,6 +27,7 @@ import javassist.bytecode.AccessFlag;
 import javassist.bytecode.ClassFile;
 import org.junit.Test;
 
+@Deprecated
 public class SourceCodeGeneratorFactoryTest {
 
     private static final SourceCodeGeneratorFactory FACTORY = new SourceCodeGeneratorFactory();