From: Robert Varga Date: Sat, 20 Apr 2019 12:03:42 +0000 (+0200) Subject: Rework DataObjectSerializer implementations X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=2cdef8576a2e5756a2c4585fad407d081a04c9c4;p=yangtools.git Rework DataObjectSerializer implementations 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 --- diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractGenerator.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractGenerator.java index f6f37d5518..cc38139c61 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractGenerator.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractGenerator.java @@ -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. diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractStreamWriterGenerator.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractStreamWriterGenerator.java index 847260010d..d1c501f5a8 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractStreamWriterGenerator.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractStreamWriterGenerator.java @@ -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); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AugmentableDataNodeContainerEmitterSource.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AugmentableDataNodeContainerEmitterSource.java index 03bf419f0e..5e3bdd4fb4 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AugmentableDataNodeContainerEmitterSource.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AugmentableDataNodeContainerEmitterSource.java @@ -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"; diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataNodeContainerSerializerSource.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataNodeContainerSerializerSource.java index 375fe00bd7..e4261182e9 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataNodeContainerSerializerSource.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataNodeContainerSerializerSource.java @@ -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); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerGenerator.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerGenerator.java index bbace44e96..6cba594d26 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerGenerator.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerGenerator.java @@ -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. diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerPrototype.java index a3cd641644..6b51495889 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerPrototype.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerPrototype.java @@ -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(); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerSource.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerSource.java index 25ba79b376..818dfee89e 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerSource.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/DataObjectSerializerSource.java @@ -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(); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/StreamWriterGenerator.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/StreamWriterGenerator.java index 779edc9b2a..99022f36ac 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/StreamWriterGenerator.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/StreamWriterGenerator.java @@ -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"; diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/AbstractSource.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/AbstractSource.java index 64c6c500a4..75f4471015 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/AbstractSource.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/AbstractSource.java @@ -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 staticConstants = new HashSet<>(); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/StaticConstantDefinition.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/StaticConstantDefinition.java index 743b852535..b231a523db 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/StaticConstantDefinition.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/spi/StaticConstantDefinition.java @@ -19,7 +19,10 @@ import static java.util.Objects.requireNonNull; *
  • type - Java type for property
  • *
  • value - value to which property should be initialized
  • * + * + * @deprecated This class is superseded by an internal implementation. */ +@Deprecated public class StaticConstantDefinition { private final String name; diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java index 1078bda964..2c12aaa26c 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java @@ -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> { + 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, DataObjectStreamer> streamers = CacheBuilder.newBuilder().build( + new CacheLoader, 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, DataObjectSerializer> serializers = CacheBuilder.newBuilder().build( + new CacheLoader, 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 type) { + return serializers.getUnchecked(type); + } + public Entry newWriter(final InstanceIdentifier path, final NormalizedNodeStreamWriter domWriter) { final List yangArgs = new LinkedList<>(); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingNormalizedNodeCodecRegistry.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingNormalizedNodeCodecRegistry.java index 3a94529223..6952efa8ee 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingNormalizedNodeCodecRegistry.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingNormalizedNodeCodecRegistry.java @@ -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, DataObjectSerializer> serializers; + + private static final AtomicReferenceFieldUpdater 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 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, DataObjectSerializer> { - @Override - public DataObjectSerializer load(final Class key) { - final DataObjectSerializerImplementation prototype = generator.getSerializer(key); - return new DataObjectSerializerProxy(prototype); - } - } - - private final class DataObjectSerializerProxy - implements DataObjectSerializer, Delegator { - 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 extends AbstractBindingLazyContainerNode { 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 index 0000000000..f48ade1b21 --- /dev/null +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamer.java @@ -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 DataObject type + */ +@Beta +public abstract class DataObjectStreamer 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>, 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>, Augmentation> aug : augmentations.entrySet()) { + emitAugmentation(aug.getKey(), aug.getValue(), writer, registry); + } + } + + private static Map>, 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 void streamChoice(final Class choiceClass, + final DataObjectSerializerRegistry registry, final BindingStreamEventWriter writer, final C value) + throws IOException { + if (value != null) { + final Class 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 void streamContainer(final DataObjectStreamer 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 void streamList(final Class childClass, + final DataObjectStreamer childStreamer, final DataObjectSerializerRegistry registry, + final BindingStreamEventWriter writer, final List value) throws IOException { + if (value != null) { + writer.startUnkeyedList(childClass, value.size()); + commonStreamList(registry, writer, childStreamer, value); + } + } + + protected static final > void streamMap(final Class childClass, + final DataObjectStreamer childStreamer, final DataObjectSerializerRegistry registry, + final BindingStreamEventWriter writer, final List value) throws IOException { + if (value != null) { + writer.startMapNode(childClass, value.size()); + commonStreamList(registry, writer, childStreamer, value); + } + } + + protected static final > void streamOrderedMap(final Class childClass, + final DataObjectStreamer childStreamer, final DataObjectSerializerRegistry registry, + final BindingStreamEventWriter writer, final List value) throws IOException { + if (value != null) { + writer.startOrderedMapNode(childClass, value.size()); + commonStreamList(registry, writer, childStreamer, value); + } + } + + private static void commonStreamList(final DataObjectSerializerRegistry registry, + final BindingStreamEventWriter writer, final DataObjectStreamer childStreamer, + final Collection 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 index 0000000000..e75ee77e4c --- /dev/null +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamerBridge.java @@ -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 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 index 0000000000..f958c15fb3 --- /dev/null +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectStreamerCustomizer.java @@ -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> constants = new HashMap<>(); + private final ImmutableMap 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 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> 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> 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> 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 target = verifyNotNull(constants.get(methodName), "Cannot resolve type of %s", + methodName); + return verifyNotNull(registry.getDataObjectSerializer(target), "Cannot find serializer for %s", target); + } + + private List> emitChildren(final StringBuilder sb, final CodecClassLoader loader, + final CtClass generated) throws CannotCompileException { + final List> 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 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 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 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 collectAllProperties(final GeneratedType type) { + final Map props = new HashMap<>(); + collectAllProperties(type, props); + return ImmutableMap.copyOf(props); + } + + private static void collectAllProperties(final GeneratedType type, final Map 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); + } + } + } +} diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/NodeCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/NodeCodecContext.java index 5944d7951e..95f308fe61 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/NodeCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/NodeCodecContext.java @@ -83,6 +83,8 @@ abstract class NodeCodecContext implements BindingCodecTreeNode { */ @NonNull CodecClassLoader getLoader(); + @NonNull DataObjectStreamer getDataObjectSerializer(Class type); + DataObjectSerializer getEventStreamSerializer(Class type); } diff --git a/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AbstractBindingCodecTest.java b/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AbstractBindingCodecTest.java index 766523b8e2..6176aa06d9 100644 --- a/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AbstractBindingCodecTest.java +++ b/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AbstractBindingCodecTest.java @@ -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()); } } diff --git a/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AugmentationClassDiscoveredAfterCodecTest.java b/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AugmentationClassDiscoveredAfterCodecTest.java index 6152808357..297d59ae7c 100644 --- a/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AugmentationClassDiscoveredAfterCodecTest.java +++ b/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/AugmentationClassDiscoveredAfterCodecTest.java @@ -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"); diff --git a/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/ExceptionReportingTest.java b/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/ExceptionReportingTest.java index eaa748b8e5..f1be7157d4 100644 --- a/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/ExceptionReportingTest.java +++ b/binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/test/ExceptionReportingTest.java @@ -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; } }