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;
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;
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);
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;
@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);
}
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;
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<>();
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;
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;
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);
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;
@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());
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;
@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());
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;
}
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;
return classPool;
}
+ @Deprecated
public void setClassPool(final ClassPool classPool) {
this.classPool = classPool;
}
-
}
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;
private BindingToNormalizedNodeCodec codec;
private final ListeningExecutorService executor;
- private final ClassPool classPool;
private final boolean startWithSchema;
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;
}
}
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);
return dataBroker;
}
- public void setSchemaModuleInfos(Set<YangModuleInfo> moduleInfos) {
+ public void setSchemaModuleInfos(final Set<YangModuleInfo> moduleInfos) {
this.schemaModuleInfos = moduleInfos;
}
}
/**
* 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.
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);
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";
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@Deprecated
abstract class DataNodeContainerSerializerSource extends DataObjectSerializerSource {
private static final Logger LOG = LoggerFactory.getLogger(DataNodeContainerSerializerSource.class);
/**
* 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.
* 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();
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();
* 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";
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<>();
* <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;
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;
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;
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;
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;
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;
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<>();
*/
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;
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;
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;
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() {
}
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
}
}
- 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> {
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+ }
+}
*/
@NonNull CodecClassLoader getLoader();
+ @NonNull DataObjectStreamer<?> getDataObjectSerializer(Class<?> type);
+
DataObjectSerializer getEventStreamSerializer(Class<?> type);
}
*/
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());
}
}
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;
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");
*/
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;
}
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;
}
}
/**
* 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 {
/**
import javassist.CannotCompileException;
import javassist.CtClass;
+@Deprecated
public interface ClassGenerator {
void process(CtClass cls) throws CannotCompileException;
}
*/
package org.opendaylight.mdsal.binding.generator.util;
+@Deprecated
public class CodeGenerationException extends RuntimeException {
private static final long serialVersionUID = 1L;
* 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;
* 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);
import javassist.CtField;
+@Deprecated
public interface FieldGenerator {
void process(CtField field);
}
/**
* 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);
* 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;
*
* @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) {
}
}
* 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;
* 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 {
/**
* 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";
import javassist.NotFoundException;
import org.junit.Test;
+@Deprecated
public class JavassistUtilsTest {
@Test
import javassist.bytecode.ClassFile;
import org.junit.Test;
+@Deprecated
public class SourceCodeGeneratorFactoryTest {
private static final SourceCodeGeneratorFactory FACTORY = new SourceCodeGeneratorFactory();