*/
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.base.Preconditions;
-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.time.Instant;
import java.util.AbstractMap.SimpleEntry;
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.binding.runtime.api.BindingRuntimeContext;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
-import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
+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.api.BindingNormalizedNodeWriterFactory;
-import org.opendaylight.mdsal.binding.dom.codec.gen.impl.DataObjectSerializerGenerator;
-import org.opendaylight.mdsal.binding.dom.codec.util.AbstractBindingLazyContainerNode;
-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.mdsal.binding.dom.codec.api.BindingStreamEventWriter;
+import org.opendaylight.mdsal.binding.dom.codec.spi.AbstractBindingLazyContainerNode;
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.opendaylight.yangtools.yang.binding.Notification;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ValueNode;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerRegistry,
- BindingCodecTreeFactory, BindingNormalizedNodeWriterFactory,
- BindingNormalizedNodeSerializer {
+ 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(final DataObjectSerializerGenerator generator) {
- this.generator = Preconditions.checkNotNull(generator);
- this.serializers = CacheBuilder.newBuilder().weakKeys().build(new GeneratorLoader());
+ public BindingNormalizedNodeCodecRegistry() {
+
+ }
+
+ public BindingNormalizedNodeCodecRegistry(final BindingRuntimeContext codecContext) {
+ this();
+ onBindingRuntimeContextUpdated(codecContext);
}
@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)) {
+ 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
}
@Override
+ @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
public ContainerNode toNormalizedNodeNotification(final Notification data) {
// FIXME: Should the cast to DataObject be necessary?
return serializeDataObject((DataObject) data,
}
@Override
+ @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
public ContainerNode toNormalizedNodeRpcData(final DataContainer data) {
// FIXME: Should the cast to DataObject be necessary?
return serializeDataObject((DataObject) data, this::newRpcWriter);
final NormalizedNodeResult result = new NormalizedNodeResult();
// We create DOM stream writer which produces normalized nodes
final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+ final Class<? extends DataObject> type = data.implementedInterface();
@SuppressWarnings("unchecked")
- final Class<? extends DataObject> type = (Class<? extends DataObject>) data.getImplementedInterface();
final BindingStreamEventWriter writer = newWriter.apply((Class<T>)type, domWriter);
try {
getSerializer(type).serialize(data, writer);
return (ContainerNode) result.getResult();
}
- private static boolean isBindingRepresentable(final NormalizedNode<?, ?> data) {
- if (data instanceof ChoiceNode) {
- return false;
- }
- if (data instanceof LeafNode<?>) {
- return false;
- }
- if (data instanceof LeafSetNode) {
- return false;
- }
- if (data instanceof LeafSetEntryNode<?>) {
- return false;
- }
- if (data instanceof MapNode) {
- return false;
- }
- if (data instanceof UnkeyedListNode) {
- return false;
- }
-
- return true;
+ private static boolean notBindingRepresentable(final NormalizedNode<?, ?> data) {
+ // ValueNode covers LeafNode and LeafSetEntryNode
+ return data instanceof ValueNode
+ || data instanceof MapNode || data instanceof UnkeyedListNode
+ || data instanceof ChoiceNode
+ || data instanceof LeafSetNode;
}
@Override
public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path,
final NormalizedNode<?, ?> data) {
- if (!isBindingRepresentable(data)) {
+ if (notBindingRepresentable(data)) {
return null;
}
final List<PathArgument> builder = new ArrayList<>();
- final NodeCodecContext<?> codec = codecContext.getCodecContextNode(path, builder);
+ final BindingDataObjectCodecTreeNode<?> codec = codecContext.getCodecContextNode(path, builder);
if (codec == null) {
if (data != null) {
LOG.warn("Path {} does not have a binding equivalent, should have been caught earlier ({})", path,
return codec.deserialize(data);
}
+ @Override
+ public Notification fromNormalizedNodeNotification(final SchemaPath path, final ContainerNode data,
+ final Instant eventInstant) {
+ if (eventInstant == null) {
+ return fromNormalizedNodeNotification(path, data);
+ }
+
+ final NotificationCodecContext<?> codec = codecContext.getNotificationContext(path);
+ return codec.deserialize(data, eventInstant);
+ }
+
@Override
public DataObject fromNormalizedNodeRpcData(final SchemaPath path, final ContainerNode data) {
final RpcInputCodec<?> codec = codecContext.getRpcInputCodec(path);
return new DeserializeFunction<>(ctx);
}
- @Override
- public BindingCodecTree create(final BindingRuntimeContext context) {
- return new BindingCodecContext(context, this);
- }
-
- @Override
- @SuppressWarnings("checkstyle:illegalCatch")
- public BindingCodecTree create(final SchemaContext context, final Class<?>... bindingClasses) {
- final ModuleInfoBackedContext strategy = ModuleInfoBackedContext.create();
- for (final Class<?> bindingCls : bindingClasses) {
- try {
- strategy.registerModuleInfo(BindingReflections.getModuleInfo(bindingCls));
- } catch (final Exception e) {
- throw new IllegalStateException(
- "Could not create BindingRuntimeContext from class " + bindingCls.getName(), e);
- }
- }
- final BindingRuntimeContext runtimeCtx = BindingRuntimeContext.create(strategy, context);
- return create(runtimeCtx);
- }
-
-
private static final class DeserializeFunction<T> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
private final DataObjectCodecContext<?,?> ctx;
}
}
- 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> {