Binding2 - Add ActionServiceAdapter 05/75205/4
authorJie Han <han.jie@zte.com.cn>
Wed, 15 Aug 2018 06:20:58 +0000 (14:20 +0800)
committerJie Han <han.jie@zte.com.cn>
Tue, 21 Aug 2018 01:40:57 +0000 (09:40 +0800)
Add ActionServiceAdapter to adapt DOMActionService.

Change-Id: I303ab2007561f2b348d4e691fa04d9b49f0eaf1c
Signed-off-by: Jie Han <han.jie@zte.com.cn>
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/ActionServiceAdapter.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationProviderServiceAdapter.java
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationServiceAdapter.java
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMActionResultFuture.java
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMRpcResultFuture.java
binding2/mdsal-binding2-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/test/BindingTestContext.java

diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/ActionServiceAdapter.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/ActionServiceAdapter.java
new file mode 100644 (file)
index 0000000..7b82d4a
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2017 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.javav2.dom.adapter.impl.operation;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.serialized.LazySerializedContainerNode;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Action;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Input;
+import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Output;
+import org.opendaylight.mdsal.binding.javav2.spec.base.RpcCallback;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMActionResult;
+import org.opendaylight.mdsal.dom.api.DOMActionService;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+@Beta
+class ActionServiceAdapter implements InvocationHandler {
+
+    private final Class<? extends Action<? extends TreeNode, ?, ?, ?>> type;
+    private final BindingToNormalizedNodeCodec codec;
+    private final DOMActionService delegate;
+    private final Action<? extends TreeNode, ?, ?, ?> proxy;
+    private final SchemaPath path;
+
+    ActionServiceAdapter(final Class<? extends Action<? extends TreeNode, ?, ?, ?>> type,
+            final BindingToNormalizedNodeCodec codec, final DOMActionService domService) {
+        this.type = requireNonNull(type);
+        this.codec = requireNonNull(codec);
+        this.delegate = requireNonNull(domService);
+        this.path = getCodec().getActionPath(type);
+        proxy = (Action<? extends TreeNode, ?, ?, ?>) Proxy.newProxyInstance(type.getClassLoader(),
+            new Class[] { type }, this);
+    }
+
+    public BindingToNormalizedNodeCodec getCodec() {
+        return codec;
+    }
+
+    public DOMActionService getDelegate() {
+        return delegate;
+    }
+
+    Action<? extends TreeNode, ?, ?, ?> getProxy() {
+        return proxy;
+    }
+
+    public Class<? extends Action<? extends TreeNode, ?, ?, ?>> getType() {
+        return type;
+    }
+
+    public SchemaPath getPath() {
+        return path;
+    }
+
+    @Override
+    @SuppressWarnings("checkstyle:hiddenField")
+    public Object invoke(final Object proxy, final Method method, final Object[] args) {
+
+        switch (method.getName()) {
+            case "equals":
+                if (args.length == 1) {
+                    return proxy == args[0];
+                }
+                break;
+            case "hashCode":
+                if (args.length == 0) {
+                    return System.identityHashCode(proxy);
+                }
+                break;
+            case "toString":
+                if (args.length == 0) {
+                    return type.getName() + "$Adapter{delegate=" + getDelegate() + "}";
+                }
+                break;
+            case "invoke":
+                if (args.length == 2) {
+                    final Input<?> input = (Input<?>) requireNonNull(args[0]);
+                    final InstanceIdentifier<?> path = (InstanceIdentifier<?>) requireNonNull(args[1]);
+                    final RpcCallback<Output> callback = (RpcCallback<Output>) requireNonNull(args[2]);
+
+                    final FluentFuture<? extends DOMActionResult> future = getDelegate().invokeAction(getPath(),
+                        new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, getCodec().toNormalized(path)),
+                        (ContainerNode) LazySerializedContainerNode.create(getPath(), (TreeNode) input,
+                            getCodec().getCodecRegistry()));
+                    //FIXME:this part is ugly, how to bridge FluentFuture and RpcCallback better?
+                    // Invocation returned a future we know about -- return that future instead
+                    if (future instanceof LazyDOMActionResultFuture) {
+                        ListenableFuture<RpcResult<?>> bindingFuture =
+                            ((LazyDOMActionResultFuture) future).getBindingFuture();
+                        Futures.addCallback(bindingFuture, new FutureCallback<RpcResult<?>>() {
+
+                            @Override
+                            public void onSuccess(final RpcResult<?> result) {
+                                if (result.isSuccessful()) {
+                                    callback.onSuccess((Output) result.getResult());
+                                } else {
+                                    //FIXME: It's not suitable to do this way here. It's better for
+                                    // 'onFailure' to accept Collection<RpcError> as input.
+                                    result.getErrors().forEach(e -> callback.onFailure(e.getCause()));
+                                }
+                            }
+
+                            @Override
+                            public void onFailure(final Throwable throwable) {
+                                callback.onFailure(throwable);
+                            }
+                        }, MoreExecutors.directExecutor());
+                    } else {
+                        Futures.addCallback(future, new FutureCallback<DOMActionResult>() {
+
+                            @Override
+                            public void onSuccess(final DOMActionResult result) {
+                                if (result.getErrors().isEmpty()) {
+                                    callback.onSuccess((Output) getCodec().fromNormalizedNodeOperationData(getPath(),
+                                        result.getOutput().get()));
+                                } else {
+                                    result.getErrors().forEach(e -> callback.onFailure(e.getCause()));
+                                }
+                            }
+
+                            @Override
+                            public void onFailure(final Throwable throwable) {
+                                callback.onFailure(throwable);
+                            }
+                        }, MoreExecutors.directExecutor());
+                    }
+                }
+                break;
+            default:
+                break;
+        }
+
+        throw new UnsupportedOperationException("Method " + method.toString() + "is unsupported.");
+    }
+}
index dd70882149c3a1e823c3a49941e7cbe720202b3e..4b2f2f0e961f02dd99618af181f88f6e439fbbf7 100644 (file)
@@ -7,8 +7,9 @@
  */
 package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.util.concurrent.FluentFuture;
 import com.google.common.util.concurrent.SettableFuture;
@@ -57,7 +58,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
-//FIXME missing support of Action operation (dependence on support of Yang 1.1 in DOM part of MD-SAL)
 /**
  * Operation service provider adapter.
  */
@@ -132,8 +132,8 @@ public class BindingDOMOperationProviderServiceAdapter implements RpcActionProvi
 
         AbstractImplAdapter(final BindingNormalizedNodeCodecRegistry codec, final Class<? extends Operation> clazz,
                    final D delegate) {
-            this.codec = Preconditions.checkNotNull(codec);
-            this.delegate = Preconditions.checkNotNull(delegate);
+            this.codec = requireNonNull(codec);
+            this.delegate = requireNonNull(delegate);
             inputQname = QName.create(BindingReflections.getQNameModule(clazz), "input").intern();
         }
 
index 251f4fefcd65781baef98f14ce9bc85c955266c7..5a37937e955fbcbb2910acf0ba4d85b27b28d385 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
@@ -23,13 +25,12 @@ import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedN
 import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
 import org.opendaylight.mdsal.binding.javav2.spec.base.Action;
 import org.opendaylight.mdsal.binding.javav2.spec.base.ListAction;
-import org.opendaylight.mdsal.binding.javav2.spec.base.Operation;
 import org.opendaylight.mdsal.binding.javav2.spec.base.Rpc;
 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.mdsal.dom.api.DOMService;
 
-//FIXME implement after improve DOM part of MD-SAL for support of Yang 1.1
 /**
  * Adapter for operation service.
  */
@@ -38,41 +39,68 @@ public class BindingDOMOperationServiceAdapter implements RpcActionConsumerRegis
 
     public static final Factory<RpcActionConsumerRegistry> BUILDER_FACTORY = Builder::new;
 
-    private final DOMRpcService domService;
+    private final DOMRpcService domRpcService;
+    private final DOMActionService domActionService;
     private final BindingToNormalizedNodeCodec codec;
-    private final LoadingCache<Class<? extends Operation>, RpcServiceAdapter> proxies = CacheBuilder.newBuilder()
-            .weakKeys().build(new CacheLoader<Class<? extends Operation>, RpcServiceAdapter>() {
+    private final LoadingCache<Class<? extends Rpc<?, ?>>, RpcServiceAdapter> rpcProxies = CacheBuilder.newBuilder()
+            .weakKeys().build(new CacheLoader<Class<? extends Rpc<?, ?>>, RpcServiceAdapter>() {
 
                 @SuppressWarnings("unchecked")
-                private RpcServiceAdapter createProxy(final Class<? extends Operation> key) {
+                private RpcServiceAdapter createProxy(final Class<? extends Rpc<?, ?>> key) {
                     Preconditions.checkArgument(BindingReflections.isBindingClass(key));
                     Preconditions.checkArgument(key.isInterface(),
                             "Supplied Operation service type must be interface.");
                     if (Rpc.class.isAssignableFrom(key)) {
-                        return new RpcServiceAdapter((Class<? extends Rpc<?, ?>>) key, codec, domService);
+                        return new RpcServiceAdapter(key, codec, domRpcService);
                     }
-                    // TODO implement after improve DOM part of MD-SAL for support of Yang 1.1
+
                     throw new UnsupportedOperationException();
                 }
 
                 @Nonnull
                 @Override
-                public RpcServiceAdapter load(@Nonnull final Class<? extends Operation> key) throws Exception {
+                public RpcServiceAdapter load(@Nonnull final Class<? extends Rpc<?, ?>> key) {
                     return createProxy(key);
                 }
 
             });
 
-    public BindingDOMOperationServiceAdapter(final DOMRpcService domService, final BindingToNormalizedNodeCodec codec) {
-        this.domService = Preconditions.checkNotNull(domService);
-        this.codec = Preconditions.checkNotNull(codec);
+    private final LoadingCache<Class<? extends Action<? extends TreeNode, ?, ?, ?>>, ActionServiceAdapter>
+            actionProxies = CacheBuilder.newBuilder().weakKeys().build(
+                new CacheLoader<Class<? extends Action<? extends TreeNode, ?, ?, ?>>, ActionServiceAdapter>() {
+
+                        @SuppressWarnings("unchecked")
+                        private ActionServiceAdapter createProxy(
+                                final Class<? extends Action<? extends TreeNode, ?, ?, ?>> key) {
+                            Preconditions.checkArgument(BindingReflections.isBindingClass(key));
+                            Preconditions.checkArgument(key.isInterface(),
+                                "Supplied Operation service type must be interface.");
+                            if (Action.class.isAssignableFrom(key)) {
+                                return new ActionServiceAdapter(key, codec, domActionService);
+                            }
+
+                            throw new UnsupportedOperationException();
+                        }
+
+                        @Nonnull
+                        @Override
+                        public ActionServiceAdapter load(@Nonnull
+                                final Class<? extends Action<? extends TreeNode, ?, ?, ?>> key) {
+                            return createProxy(key);
+                        }
+                    });
+
+    public BindingDOMOperationServiceAdapter(final DOMRpcService domRpcService, final DOMActionService domActionService,
+             final BindingToNormalizedNodeCodec codec) {
+        this.domRpcService = requireNonNull(domRpcService);
+        this.domActionService = requireNonNull(domActionService);
+        this.codec = requireNonNull(codec);
     }
 
     @SuppressWarnings("unchecked")
     @Override
     public <T extends Rpc<?, ?>> T getRpcService(final Class<T> rpc) {
-        Preconditions.checkArgument(rpc != null, "Rpc needs to be specified.");
-        return (T) proxies.getUnchecked(rpc).getProxy();
+        return (T) rpcProxies.getUnchecked(requireNonNull(rpc)).getProxy();
     }
 
     private static final class Builder extends BindingDOMAdapterBuilder<RpcActionConsumerRegistry> {
@@ -80,25 +108,25 @@ public class BindingDOMOperationServiceAdapter implements RpcActionConsumerRegis
         @Override
         protected RpcActionConsumerRegistry createInstance(final BindingToNormalizedNodeCodec codec,
                 final ClassToInstanceMap<DOMService> delegates) {
-            final DOMRpcService domRpc = delegates.getInstance(DOMRpcService.class);
-            return new BindingDOMOperationServiceAdapter(domRpc, codec);
+            final DOMRpcService domRpcService = delegates.getInstance(DOMRpcService.class);
+            final DOMActionService domActionService = delegates.getInstance(DOMActionService.class);
+            return new BindingDOMOperationServiceAdapter(domRpcService, domActionService, codec);
         }
 
         @Override
         public Set<? extends Class<? extends DOMService>> getRequiredDelegates() {
-            return ImmutableSet.of(DOMRpcService.class);
+            return ImmutableSet.of(DOMRpcService.class, DOMActionService.class);
         }
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public <T extends Action<? extends TreeNode, ?, ?, ?>> T getActionService(final Class<T> serviceInterface) {
-        // TODO implement after improve DOM part of MD-SAL for support of Yang 1.1
-        throw new UnsupportedOperationException();
+        return (T) actionProxies.getUnchecked(requireNonNull(serviceInterface)).getProxy();
     }
 
     @Override
     public <T extends ListAction<? extends TreeNode, ?, ?, ?>> T getListActionService(final Class<T> serviceInterface) {
-        // TODO implement after improve DOM part of MD-SAL for support of Yang 1.1
-        throw new UnsupportedOperationException();
+        return getActionService(serviceInterface);
     }
 }
index 54c1748379391256ef78461455fbf76f0c1b4484..24c880ec5f0ab5a6d2fcd54ee1637ca4cd43977f 100644 (file)
@@ -7,8 +7,9 @@
  */
 package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.util.concurrent.AbstractFuture;
 import com.google.common.util.concurrent.FluentFuture;
@@ -48,8 +49,8 @@ final class LazyDOMActionResultFuture extends AbstractFuture<DOMActionResult> {
 
     private LazyDOMActionResultFuture(final ListenableFuture<RpcResult<?>> delegate,
                                       final BindingNormalizedNodeCodecRegistry codec) {
-        this.bindingFuture = Preconditions.checkNotNull(delegate, "delegate");
-        this.codec = Preconditions.checkNotNull(codec, "codec");
+        this.bindingFuture = requireNonNull(delegate, "delegate");
+        this.codec = requireNonNull(codec, "codec");
     }
 
     static FluentFuture<DOMActionResult> create(final BindingNormalizedNodeCodecRegistry codec,
index 0df3547845c1233c160bf26a17e69dd04a9035b8..a37279c24fb110f7304f96c64e2a1cddbc3468dd 100644 (file)
@@ -7,8 +7,9 @@
  */
 package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.AbstractFuture;
 import com.google.common.util.concurrent.FluentFuture;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -48,8 +49,8 @@ final class LazyDOMRpcResultFuture extends AbstractFuture<DOMRpcResult> {
 
     private LazyDOMRpcResultFuture(final ListenableFuture<RpcResult<?>> delegate,
                                    final BindingNormalizedNodeCodecRegistry codec) {
-        this.bindingFuture = Preconditions.checkNotNull(delegate, "delegate");
-        this.codec = Preconditions.checkNotNull(codec, "codec");
+        this.bindingFuture = requireNonNull(delegate, "delegate");
+        this.codec = requireNonNull(codec, "codec");
     }
 
     static FluentFuture<DOMRpcResult> create(final BindingNormalizedNodeCodecRegistry codec,
index 1e42a9a1d554a6ed7eed55e28ef2c9c4b715bd3b..5c69781ce0a526e97c680a8106a470faf5249693 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflectio
 import org.opendaylight.mdsal.binding.javav2.spec.runtime.YangModuleInfo;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
+import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.mdsal.dom.api.DOMNotificationPublishService;
@@ -119,7 +120,7 @@ public class BindingTestContext implements AutoCloseable {
     public void startBindingBroker() {
         checkState(executor != null, "Executor needs to be set");
 
-        baConsumerRpc = new BindingDOMOperationServiceAdapter(getDomRpcInvoker(), codec);
+        baConsumerRpc = new BindingDOMOperationServiceAdapter(getDomRpcInvoker(), getDomActionService(), codec);
         baProviderRpc = new BindingDOMOperationProviderServiceAdapter(getDomRpcRegistry(), getDomActionRegistry(),
             codec);
         final MountPointService mountService = new BindingDOMMountPointServiceAdapter(biMountImpl, codec);
@@ -208,6 +209,10 @@ public class BindingTestContext implements AutoCloseable {
         return domRouter.getRpcService();
     }
 
+    public DOMActionService getDomActionService() {
+        return domRouter.getActionService();
+    }
+
     @Override
     public void close() throws Exception {