Refactor binding-dom-adapter
[mdsal.git] / binding / mdsal-binding-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / dom / adapter / BindingToNormalizedNodeCodec.java
diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingToNormalizedNodeCodec.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingToNormalizedNodeCodec.java
deleted file mode 100644 (file)
index d296fa2..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.binding.dom.adapter;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterators;
-import java.lang.reflect.Method;
-import java.time.Instant;
-import java.util.AbstractMap.SimpleEntry;
-import java.util.Collection;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.binding.runtime.api.BindingRuntimeContext;
-import org.opendaylight.binding.runtime.api.BindingRuntimeGenerator;
-import org.opendaylight.binding.runtime.api.ClassLoadingStrategy;
-import org.opendaylight.binding.runtime.api.DefaultBindingRuntimeContext;
-import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
-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.MissingSchemaException;
-import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
-import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
-import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
-import org.opendaylight.mdsal.dom.api.DOMSchemaService;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-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.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.binding.Notification;
-import org.opendaylight.yangtools.yang.binding.RpcInput;
-import org.opendaylight.yangtools.yang.binding.RpcOutput;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
-import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
-import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
-import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextListener;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A combinations of {@link BindingCodecTreeFactory} and {@link BindingNormalizedNodeSerializer}, with internal
- * caching of instance identifiers.
- *
- * <p>
- * NOTE: this class is non-final to allow controller adapter migration without duplicated code.
- */
-@Singleton
-public class BindingToNormalizedNodeCodec implements BindingNormalizedNodeSerializer, EffectiveModelContextListener,
-        AutoCloseable {
-
-    private static final long WAIT_DURATION_SEC = 5;
-    private static final Logger LOG = LoggerFactory.getLogger(BindingToNormalizedNodeCodec.class);
-
-    private final LoadingCache<InstanceIdentifier<?>, YangInstanceIdentifier> iiCache = CacheBuilder.newBuilder()
-            .softValues().build(new CacheLoader<InstanceIdentifier<?>, YangInstanceIdentifier>() {
-                @Override
-                public YangInstanceIdentifier load(final InstanceIdentifier<?> key) {
-                    return toYangInstanceIdentifierBlocking(key);
-                }
-            });
-    private final BindingNormalizedNodeCodecRegistry codecRegistry;
-    private final ClassLoadingStrategy classLoadingStrategy;
-    private final BindingRuntimeGenerator generator;
-    private final FutureSchema futureSchema;
-
-    private ListenerRegistration<?> listenerRegistration;
-
-    @Inject
-    public BindingToNormalizedNodeCodec(final BindingRuntimeGenerator generator,
-            final ClassLoadingStrategy classLoadingStrategy, final BindingNormalizedNodeCodecRegistry codecRegistry) {
-        this(generator, classLoadingStrategy, codecRegistry, false);
-    }
-
-    @Beta
-    public BindingToNormalizedNodeCodec(final BindingRuntimeContext runtimeContext) {
-        generator = (final SchemaContext context) -> {
-            throw new UnsupportedOperationException("Static context assigned");
-        };
-        classLoadingStrategy = runtimeContext.getStrategy();
-        codecRegistry = new BindingNormalizedNodeCodecRegistry(runtimeContext);
-        // TODO: this should have a specialized constructor or not be needed
-        futureSchema = FutureSchema.create(0, TimeUnit.SECONDS, false);
-        futureSchema.onRuntimeContextUpdated(runtimeContext);
-    }
-
-    public BindingToNormalizedNodeCodec(final BindingRuntimeGenerator generator,
-            final ClassLoadingStrategy classLoadingStrategy, final BindingNormalizedNodeCodecRegistry codecRegistry,
-            final boolean waitForSchema) {
-        this.generator = requireNonNull(generator, "generator");
-        this.classLoadingStrategy = requireNonNull(classLoadingStrategy, "classLoadingStrategy");
-        this.codecRegistry = requireNonNull(codecRegistry, "codecRegistry");
-        this.futureSchema = FutureSchema.create(WAIT_DURATION_SEC, TimeUnit.SECONDS, waitForSchema);
-    }
-
-    public static BindingToNormalizedNodeCodec newInstance(final BindingRuntimeGenerator generator,
-            final ClassLoadingStrategy classLoadingStrategy, final DOMSchemaService schemaService) {
-        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry();
-        BindingToNormalizedNodeCodec instance = new BindingToNormalizedNodeCodec(generator, classLoadingStrategy,
-            codecRegistry, true);
-        instance.listenerRegistration = schemaService.registerSchemaContextListener(instance);
-        return instance;
-    }
-
-    protected YangInstanceIdentifier toYangInstanceIdentifierBlocking(
-            final InstanceIdentifier<? extends DataObject> binding) {
-        try {
-            return codecRegistry.toYangInstanceIdentifier(binding);
-        } catch (final MissingSchemaException e) {
-            waitForSchema(decompose(binding), e);
-            return codecRegistry.toYangInstanceIdentifier(binding);
-        }
-    }
-
-    @Override
-    public final YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding) {
-        return codecRegistry.toYangInstanceIdentifier(binding);
-    }
-
-    protected YangInstanceIdentifier toYangInstanceIdentifierCached(final InstanceIdentifier<?> binding) {
-        return iiCache.getUnchecked(binding);
-    }
-
-    @Override
-    public final <T extends DataObject> Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
-            final InstanceIdentifier<T> path, final T data) {
-        try {
-            return codecRegistry.toNormalizedNode(path, data);
-        } catch (final MissingSchemaException e) {
-            waitForSchema(decompose(path), e);
-            return codecRegistry.toNormalizedNode(path, data);
-        }
-    }
-
-    @Override
-    public final Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path,
-            final NormalizedNode<?, ?> data) {
-        return codecRegistry.fromNormalizedNode(path, data);
-    }
-
-    @Override
-    public final Notification fromNormalizedNodeNotification(final SchemaPath path, final ContainerNode data) {
-        return codecRegistry.fromNormalizedNodeNotification(path, data);
-    }
-
-    @Override
-    public final Notification fromNormalizedNodeNotification(final SchemaPath path, final ContainerNode data,
-            final Instant eventInstant) {
-        return codecRegistry.fromNormalizedNodeNotification(path, data, eventInstant);
-    }
-
-    @Override
-    public final DataObject fromNormalizedNodeRpcData(final SchemaPath path, final ContainerNode data) {
-        return codecRegistry.fromNormalizedNodeRpcData(path, data);
-    }
-
-    @Override
-    public <T extends RpcInput> T fromNormalizedNodeActionInput(final Class<? extends Action<?, ?, ?>> action,
-            final ContainerNode input) {
-        return codecRegistry.fromNormalizedNodeActionInput(action, input);
-    }
-
-    @Override
-    public <T extends RpcOutput> T fromNormalizedNodeActionOutput(final Class<? extends Action<?, ?, ?>> action,
-            final ContainerNode output) {
-        return codecRegistry.fromNormalizedNodeActionOutput(action, output);
-    }
-
-    @Override
-    public final <T extends DataObject> InstanceIdentifier<T> fromYangInstanceIdentifier(
-            final YangInstanceIdentifier dom) {
-        return codecRegistry.fromYangInstanceIdentifier(dom);
-    }
-
-    @Override
-    public final ContainerNode toNormalizedNodeNotification(final Notification data) {
-        return codecRegistry.toNormalizedNodeNotification(data);
-    }
-
-    @Override
-    public final ContainerNode toNormalizedNodeRpcData(final DataContainer data) {
-        return codecRegistry.toNormalizedNodeRpcData(data);
-    }
-
-    @Override
-    public ContainerNode toNormalizedNodeActionInput(final Class<? extends Action<?, ?, ?>> action,
-            final RpcInput input) {
-        return codecRegistry.toNormalizedNodeActionInput(action, input);
-    }
-
-    @Override
-    public ContainerNode toNormalizedNodeActionOutput(final Class<? extends Action<?, ?, ?>> action,
-            final RpcOutput output) {
-        return codecRegistry.toNormalizedNodeActionOutput(action, output);
-    }
-
-    @Override
-    public BindingLazyContainerNode<RpcInput> toLazyNormalizedNodeActionInput(
-            final Class<? extends Action<?, ?, ?>> action, final NodeIdentifier identifier, final RpcInput input) {
-        return codecRegistry.toLazyNormalizedNodeActionInput(action, identifier, input);
-    }
-
-    @Override
-    public BindingLazyContainerNode<RpcOutput> toLazyNormalizedNodeActionOutput(
-            final Class<? extends Action<?, ?, ?>> action, final NodeIdentifier identifier, final RpcOutput output) {
-        return codecRegistry.toLazyNormalizedNodeActionOutput(action, identifier, output);
-    }
-
-    /**
-     * Returns a Binding-Aware instance identifier from normalized
-     * instance-identifier if it is possible to create representation.
-     *
-     * <p>
-     * Returns Optional.empty for cases where target is mixin node except
-     * augmentation.
-     */
-    public final Optional<InstanceIdentifier<? extends DataObject>> toBinding(final YangInstanceIdentifier normalized)
-                    throws DeserializationException {
-        try {
-            return Optional.ofNullable(codecRegistry.fromYangInstanceIdentifier(normalized));
-        } catch (final IllegalArgumentException e) {
-            return Optional.empty();
-        }
-    }
-
-    @Override
-    public void onModelContextUpdated(final EffectiveModelContext newModelContext) {
-        final BindingRuntimeContext runtimeContext = DefaultBindingRuntimeContext.create(
-            generator.generateTypeMapping(newModelContext), classLoadingStrategy);
-        codecRegistry.onBindingRuntimeContextUpdated(runtimeContext);
-        futureSchema.onRuntimeContextUpdated(runtimeContext);
-    }
-
-    public final BindingNormalizedNodeCodecRegistry getCodecRegistry() {
-        return codecRegistry;
-    }
-
-    @Override
-    @PreDestroy
-    public void close() {
-        if (listenerRegistration != null) {
-            listenerRegistration.close();
-        }
-    }
-
-    // FIXME: This should be probably part of Binding Runtime context
-    public final ImmutableBiMap<Method, SchemaPath> getRpcMethodToSchemaPath(final Class<? extends RpcService> key) {
-        final Module module = getModuleBlocking(key);
-        final ImmutableBiMap.Builder<Method, SchemaPath> ret = ImmutableBiMap.builder();
-        try {
-            for (final RpcDefinition rpcDef : module.getRpcs()) {
-                final Method method = findRpcMethod(key, rpcDef);
-                ret.put(method, rpcDef.getPath());
-            }
-        } catch (final NoSuchMethodException e) {
-            throw new IllegalStateException("Rpc defined in model does not have representation in generated class.", e);
-        }
-        return ret.build();
-    }
-
-    protected ImmutableBiMap<Method, RpcDefinition> getRpcMethodToSchema(final Class<? extends RpcService> key) {
-        final Module module = getModuleBlocking(key);
-        final ImmutableBiMap.Builder<Method, RpcDefinition> ret = ImmutableBiMap.builder();
-        try {
-            for (final RpcDefinition rpcDef : module.getRpcs()) {
-                final Method method = findRpcMethod(key, rpcDef);
-                ret.put(method, rpcDef);
-            }
-        } catch (final NoSuchMethodException e) {
-            throw new IllegalStateException("Rpc defined in model does not have representation in generated class.", e);
-        }
-        return ret.build();
-    }
-
-    private Module getModuleBlocking(final Class<?> modeledClass) {
-        final QNameModule moduleName = BindingReflections.getQNameModule(modeledClass);
-        BindingRuntimeContext localRuntimeContext = runtimeContext();
-        Module module = localRuntimeContext == null ? null :
-            localRuntimeContext.getSchemaContext().findModule(moduleName).orElse(null);
-        if (module == null && futureSchema.waitForSchema(moduleName)) {
-            localRuntimeContext = runtimeContext();
-            checkState(localRuntimeContext != null, "BindingRuntimeContext is not available.");
-            module = localRuntimeContext.getSchemaContext().findModule(moduleName).orElse(null);
-        }
-        if (module != null) {
-            return module;
-        }
-
-        LOG.debug("Schema for {} is not available; expected module name: {}; BindingRuntimeContext: {}",
-                modeledClass, moduleName, localRuntimeContext);
-        throw new IllegalStateException(String.format("Schema for %s is not available; expected module name: %s; "
-                + "full BindingRuntimeContext available in debug log", modeledClass, moduleName));
-    }
-
-    private void waitForSchema(final Collection<Class<?>> binding, final MissingSchemaException exception) {
-        LOG.warn("Blocking thread to wait for schema convergence updates for {} {}", futureSchema.getDuration(),
-            futureSchema.getUnit());
-        if (!futureSchema.waitForSchema(binding)) {
-            throw exception;
-        }
-    }
-
-    private Method findRpcMethod(final Class<? extends RpcService> key, final RpcDefinition rpcDef)
-            throws NoSuchMethodException {
-        final String methodName = BindingMapping.getRpcMethodName(rpcDef.getQName());
-        final Class<?> inputClz = runtimeContext().getClassForSchema(rpcDef.getInput());
-        return key.getMethod(methodName, inputClz);
-    }
-
-    protected @NonNull Entry<InstanceIdentifier<?>, BindingDataObjectCodecTreeNode<?>> getSubtreeCodec(
-            final YangInstanceIdentifier domIdentifier) {
-
-        final BindingCodecTree currentCodecTree = codecRegistry.getCodecContext();
-        final InstanceIdentifier<?> bindingPath = codecRegistry.fromYangInstanceIdentifier(domIdentifier);
-        checkArgument(bindingPath != null);
-        /**
-         * If we are able to deserialize YANG instance identifier, getSubtreeCodec must
-         * return non-null value.
-         */
-        final BindingDataObjectCodecTreeNode<?> codecContext = currentCodecTree.getSubtreeCodec(bindingPath);
-        return new SimpleEntry<>(bindingPath, codecContext);
-    }
-
-    final SchemaPath getActionPath(final Class<? extends Action<?, ?, ?>> type) {
-        final ActionDefinition schema = runtimeContext().getActionDefinition(type);
-        checkArgument(schema != null, "Failed to find schema for %s", type);
-        return schema.getPath();
-    }
-
-    final BindingRuntimeContext runtimeContext() {
-        return futureSchema.runtimeContext();
-    }
-
-    private static Collection<Class<?>> decompose(final InstanceIdentifier<?> path) {
-        return ImmutableSet.copyOf(Iterators.transform(path.getPathArguments().iterator(), PathArgument::getType));
-    }
-
-    protected Collection<DOMDataTreeIdentifier> toDOMDataTreeIdentifiers(
-            final Collection<DataTreeIdentifier<?>> subtrees) {
-        return subtrees.stream().map(this::toDOMDataTreeIdentifier).collect(Collectors.toSet());
-    }
-
-    protected DOMDataTreeIdentifier toDOMDataTreeIdentifier(final DataTreeIdentifier<?> path) {
-        final YangInstanceIdentifier domPath = toYangInstanceIdentifierBlocking(path.getRootIdentifier());
-        return new DOMDataTreeIdentifier(path.getDatastoreType(), domPath);
-    }
-}