Allow Binding/DOM/Binding shortcuts to be disabled 16/78816/4
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 15 Dec 2018 13:14:33 +0000 (14:14 +0100)
committerRobert Varga <nite@hq.sk>
Mon, 17 Dec 2018 15:49:44 +0000 (15:49 +0000)
This adds a property-driven knob, which allows the various shortcuts
we take when crossing binding-dom-adapter to be completely disabled.

Using the knob is useful for testing and making sure applications
correctly follow the YANG model they are written against.

Change-Id: I9836304fe7878b80c769b88914300fbcf3fe08b5
JIRA: MDSAL-409
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMRpcImplementationAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/StaticConfiguration.java [new file with mode: 0644]

index 70259f29840a504180a377aca24e70593e38b9a7..2711e35cf886c93c9f354837489b598c75b0f220 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.mdsal.binding.dom.adapter;
 
 import static java.util.Objects.requireNonNull;
+import static org.opendaylight.mdsal.binding.dom.adapter.StaticConfiguration.ENABLE_CODEC_SHORTCUT;
 import static org.opendaylight.yangtools.yang.common.YangConstants.operationInputQName;
 
 import com.google.common.util.concurrent.FluentFuture;
@@ -68,7 +69,7 @@ final class ActionAdapter extends AbstractBindingAdapter<DOMActionService> imple
                         getCodec().toLazyNormalizedNodeActionInput(type, inputName, input));
 
                     // Invocation returned a future we know about -- return that future instead
-                    if (future instanceof BindingRpcFutureAware) {
+                    if (ENABLE_CODEC_SHORTCUT && future instanceof BindingRpcFutureAware) {
                         return ((BindingRpcFutureAware) future).getBindingFuture();
                     }
 
index 8167d36c643a9c5da8c042d9baa01e11d33d074a..c8428c843473cb686434a53d07180fe6b3e6a599 100644 (file)
@@ -7,7 +7,9 @@
  */
 package org.opendaylight.mdsal.binding.dom.adapter;
 
-import com.google.common.base.Preconditions;
+import static java.util.Objects.requireNonNull;
+import static org.opendaylight.mdsal.binding.dom.adapter.StaticConfiguration.ENABLE_CODEC_SHORTCUT;
+
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.util.concurrent.FluentFuture;
@@ -33,9 +35,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
 public class BindingDOMRpcImplementationAdapter implements DOMRpcImplementation {
+    private static final Cache<Class<?>, RpcServiceInvoker> SERVICE_INVOKERS = CacheBuilder.newBuilder().weakKeys()
+            .build();
 
-    private static final Cache<Class<?>, RpcServiceInvoker> SERVICE_INVOKERS
-            = CacheBuilder.newBuilder().weakKeys().build();
     // Default implementations are 0, we need to perform some translation, hence we have a slightly higher cost
     private static final int COST = 1;
 
@@ -59,8 +61,8 @@ public class BindingDOMRpcImplementationAdapter implements DOMRpcImplementation
             throw new IllegalArgumentException("Failed to create invokers for type " + type, e);
         }
 
-        this.codec = Preconditions.checkNotNull(codec);
-        this.delegate = Preconditions.checkNotNull(delegate);
+        this.codec = requireNonNull(codec);
+        this.delegate = requireNonNull(delegate);
         inputQname = YangConstants.operationInputQName(BindingReflections.getQNameModule(type)).intern();
     }
 
@@ -78,7 +80,7 @@ public class BindingDOMRpcImplementationAdapter implements DOMRpcImplementation
     }
 
     private DataObject deserialize(final SchemaPath rpcPath, final NormalizedNode<?, ?> input) {
-        if (input instanceof BindingDataAware) {
+        if (ENABLE_CODEC_SHORTCUT && input instanceof BindingDataAware) {
             return ((BindingDataAware) input).bindingData();
         }
         final SchemaPath inputSchemaPath = rpcPath.createChild(inputQname);
index f7a69b59560f7f7308a0311c8782c5ebf713e7de..1938faf875ae2c86c8e30b6b3f0eaf3278139d43 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.mdsal.binding.dom.adapter;
 
+import static java.util.Objects.requireNonNull;
+import static org.opendaylight.mdsal.binding.dom.adapter.StaticConfiguration.ENABLE_CODEC_SHORTCUT;
+
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.util.concurrent.Futures;
@@ -47,9 +50,9 @@ class RpcServiceAdapter implements InvocationHandler {
 
     RpcServiceAdapter(final Class<? extends RpcService> type, final BindingToNormalizedNodeCodec codec,
             final DOMRpcService domService) {
-        this.type = Preconditions.checkNotNull(type);
-        this.codec = Preconditions.checkNotNull(codec);
-        this.delegate = Preconditions.checkNotNull(domService);
+        this.type = requireNonNull(type);
+        this.codec = requireNonNull(codec);
+        this.delegate = requireNonNull(domService);
         final ImmutableMap.Builder<Method, RpcInvocationStrategy> rpcBuilder = ImmutableMap.builder();
         for (final Entry<Method, RpcDefinition> rpc : codec.getRpcMethodToSchema(type).entrySet()) {
             rpcBuilder.put(rpc.getKey(), createStrategy(rpc.getKey(), rpc.getValue()));
@@ -133,7 +136,7 @@ class RpcServiceAdapter implements InvocationHandler {
 
         ListenableFuture<RpcResult<?>> invoke0(final SchemaPath schemaPath, final ContainerNode input) {
             final ListenableFuture<DOMRpcResult> result = delegate.invokeRpc(schemaPath, input);
-            if (result instanceof BindingRpcFutureAware) {
+            if (ENABLE_CODEC_SHORTCUT && result instanceof BindingRpcFutureAware) {
                 return ((BindingRpcFutureAware) result).getBindingFuture();
             }
 
diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/StaticConfiguration.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/StaticConfiguration.java
new file mode 100644 (file)
index 0000000..daaee76
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, 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.adapter;
+
+import org.slf4j.LoggerFactory;
+
+/**
+ * Static JVM-wide configuration.
+ */
+final class StaticConfiguration {
+    /**
+     * When we are invoking a Binding-Aware RPC implementation, we can side-step translation through NormalizedNodes,
+     * which is an obvious performance win.
+     *
+     * <p>
+     * Unfortunately Binding Specification does not truthfully cover YANG semantics, in that grouping instantiations
+     * are not treated separately, which leads to constructs which are Binding-valid, but are actually YANG-invalid.
+     * These are usually easily rectified when identified, but the existence of this shortcut means that in single-node
+     * scenario we do not detect these mismatches and thus these issues remain unidentified -- only to break when
+     * in multi-node scenarios or the shortcut becomes otherwise ineffective.
+     *
+     * <p>
+     * We therefore allow the shortcuts to be globally disabled via a property, which is evaluated when this component
+     * loads.
+     */
+    static final boolean ENABLE_CODEC_SHORTCUT = !Boolean.getBoolean(
+        "org.opendaylight.mdsal.binding.dom.adapter.disableCodecShortcut");
+
+    static {
+        // Do not retain the logger
+        LoggerFactory.getLogger(StaticConfiguration.class).info("Binding-over-DOM codec shortcuts are {}",
+                ENABLE_CODEC_SHORTCUT ? "enabled" : "disabled");
+    }
+
+    private StaticConfiguration() {
+
+    }
+}