Binding2 - Implement RpcActionProviderService
[mdsal.git] / binding2 / mdsal-binding2-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / javav2 / dom / adapter / impl / operation / BindingDOMOperationProviderServiceAdapter.java
index 68a105f74e0ac6c9f474779ea1da817e5f227b77..dd70882149c3a1e823c3a49941e7cbe720202b3e 100644 (file)
@@ -8,27 +8,53 @@
 package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
-import java.lang.reflect.Method;
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.SettableFuture;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.mdsal.binding.javav2.api.DataTreeIdentifier;
 import org.opendaylight.mdsal.binding.javav2.api.RpcActionProviderService;
+import org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation.BindingDOMOperationProviderServiceAdapter.AbstractImplAdapter.ActionAdapter;
+import org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation.BindingDOMOperationProviderServiceAdapter.AbstractImplAdapter.RpcAdapter;
 import org.opendaylight.mdsal.binding.javav2.dom.adapter.registration.BindingDOMOperationAdapterRegistration;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
 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.runtime.reflection.BindingReflections;
 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.KeyedInstanceIdentifier;
-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.Output;
 import org.opendaylight.mdsal.binding.javav2.spec.base.Rpc;
+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.DOMActionImplementation;
+import org.opendaylight.mdsal.dom.api.DOMActionInstance;
+import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
+import org.opendaylight.mdsal.dom.api.DOMActionResult;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
 import org.opendaylight.mdsal.dom.api.DOMRpcImplementationRegistration;
 import org.opendaylight.mdsal.dom.api.DOMRpcProviderService;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+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)
@@ -41,11 +67,13 @@ public class BindingDOMOperationProviderServiceAdapter implements RpcActionProvi
     private static final Set<YangInstanceIdentifier> GLOBAL = ImmutableSet.of(YangInstanceIdentifier.builder().build());
     private final BindingToNormalizedNodeCodec codec;
     private final DOMRpcProviderService domRpcRegistry;
+    private final DOMActionProviderService domActionRegistry;
 
     public BindingDOMOperationProviderServiceAdapter(final DOMRpcProviderService domRpcRegistry,
-            final BindingToNormalizedNodeCodec codec) {
+            final DOMActionProviderService domActionRegistry, final BindingToNormalizedNodeCodec codec) {
         this.codec = codec;
         this.domRpcRegistry = domRpcRegistry;
+        this.domActionRegistry = domActionRegistry;
     }
 
     @Override
@@ -62,22 +90,18 @@ public class BindingDOMOperationProviderServiceAdapter implements RpcActionProvi
 
     private <S extends Rpc<?, ?>, T extends S> ObjectRegistration<T> register(final Class<S> type,
             final T implementation, final Collection<YangInstanceIdentifier> rpcContextPaths) {
-        final Map<SchemaPath, Method> rpcs = codec.getRPCMethodToSchemaPath(type).inverse();
-
-        final BindingDOMOperationImplementationAdapter adapter =
-                new BindingDOMOperationImplementationAdapter(codec.getCodecRegistry(), type, rpcs, implementation);
-        final Set<DOMRpcIdentifier> domRpcs = createDomRpcIdentifiers(rpcs.keySet(), rpcContextPaths);
-        final DOMRpcImplementationRegistration<?> domReg = domRpcRegistry.registerRpcImplementation(adapter, domRpcs);
+        final SchemaPath path = codec.getRpcPath(type);
+        final Set<DOMRpcIdentifier> domRpcs = createDomRpcIdentifiers(path, rpcContextPaths);
+        final DOMRpcImplementationRegistration<?> domReg = domRpcRegistry.registerRpcImplementation(
+            new RpcAdapter(codec.getCodecRegistry(), type, implementation), domRpcs);
         return new BindingDOMOperationAdapterRegistration<>(implementation, domReg);
     }
 
-    private static Set<DOMRpcIdentifier> createDomRpcIdentifiers(final Set<SchemaPath> rpcs,
+    private static Set<DOMRpcIdentifier> createDomRpcIdentifiers(final SchemaPath rpc,
             final Collection<YangInstanceIdentifier> paths) {
         final Set<DOMRpcIdentifier> ret = new HashSet<>();
         for (final YangInstanceIdentifier path : paths) {
-            for (final SchemaPath rpc : rpcs) {
-                ret.add(DOMRpcIdentifier.create(rpc, path));
-            }
+            ret.add(DOMRpcIdentifier.create(rpc, path));
         }
         return ret;
     }
@@ -91,18 +115,95 @@ public class BindingDOMOperationProviderServiceAdapter implements RpcActionProvi
     }
 
     @Override
-    public <S extends Action<? extends TreeNode, ?, ?>, T extends S, P extends TreeNode> ObjectRegistration<T>
-            registerActionImplementation(final Class<S> type, final InstanceIdentifier<P> parent,
-                    final T implementation) {
-     // TODO implement after improve DOM part of MD-SAL for support of Yang 1.1
-        throw new UnsupportedOperationException();
+    public <S extends Action<? extends TreeNode, ?, ?, ?>, T extends S, P extends TreeNode> ObjectRegistration<T>
+            registerActionImplementation(final Class<S> type, final T implementation,
+                final LogicalDatastoreType datastore, final Set<DataTreeIdentifier<P>> validNodes) {
+        final SchemaPath path = codec.getActionPath(type);
+        final ObjectRegistration<ActionAdapter> domReg = domActionRegistry.registerActionImplementation(
+            new ActionAdapter(codec.getCodecRegistry(), type, implementation),
+            DOMActionInstance.of(path, codec.toDOMDataTreeIdentifiers(validNodes)));
+        return new BindingDOMOperationAdapterRegistration<>(implementation, domReg);
     }
 
-    @Override
-    public <S extends ListAction<? extends TreeNode, ?, ?>, T extends S, P extends TreeNode, K> ObjectRegistration<T>
-            registerListActionImplementation(final Class<S> type, final KeyedInstanceIdentifier<P, K> parent,
-                    final T implementation) {
-     // TODO implement after improve DOM part of MD-SAL for support of Yang 1.1
-        throw new UnsupportedOperationException();
+    public abstract static class AbstractImplAdapter<D> {
+        protected final BindingNormalizedNodeCodecRegistry codec;
+        protected final D delegate;
+        private final QName inputQname;
+
+        AbstractImplAdapter(final BindingNormalizedNodeCodecRegistry codec, final Class<? extends Operation> clazz,
+                   final D delegate) {
+            this.codec = Preconditions.checkNotNull(codec);
+            this.delegate = Preconditions.checkNotNull(delegate);
+            inputQname = QName.create(BindingReflections.getQNameModule(clazz), "input").intern();
+        }
+
+        TreeNode deserialize(final SchemaPath path, final NormalizedNode<?, ?> input) {
+            if (input instanceof LazySerializedContainerNode) {
+                return ((LazySerializedContainerNode) input).bindingData();
+            }
+            final SchemaPath inputSchemaPath = path.createChild(inputQname);
+            return codec.fromNormalizedNodeOperationData(inputSchemaPath, (ContainerNode) input);
+        }
+
+        public static final class RpcAdapter extends AbstractImplAdapter<Rpc> implements DOMRpcImplementation {
+
+            RpcAdapter(BindingNormalizedNodeCodecRegistry codec, Class<? extends Operation> clazz,
+                    Rpc<?, ?> delegate) {
+                super(codec, clazz, delegate);
+            }
+
+            @SuppressWarnings("checkstyle:illegalCatch, unchecked")
+            @Nonnull
+            @Override
+            public FluentFuture<DOMRpcResult> invokeRpc(@Nonnull final DOMRpcIdentifier rpc,
+                                                        @Nullable final NormalizedNode<?, ?> input) {
+                final TreeNode bindingInput = input != null ? deserialize(rpc.getType(), input) : null;
+                final SettableFuture<RpcResult<?>> bindingResult = SettableFuture.create();
+                CompletableFuture.runAsync(() -> delegate.invoke((Input<?>) bindingInput,
+                    new RpcCallback<Output<?>>() {
+                        public void onSuccess(Output<?> output) {
+                            bindingResult.set(RpcResultBuilder.success(output).build());
+                        }
+
+                        public void onFailure(Throwable error) {
+                            bindingResult.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION,
+                                error.getMessage()).build());
+                        }
+                    })
+                );
+                return LazyDOMRpcResultFuture.create(codec,bindingResult);
+            }
+        }
+
+        public static final class ActionAdapter extends AbstractImplAdapter<Action>
+                implements DOMActionImplementation {
+
+            ActionAdapter(BindingNormalizedNodeCodecRegistry codec, Class<? extends Operation> clazz,
+                    Action<?, ?, ?, ?> delegate) {
+                super(codec, clazz, delegate);
+            }
+
+            @SuppressWarnings("checkstyle:illegalCatch, unchecked")
+            @Nonnull
+            public FluentFuture<? extends DOMActionResult> invokeAction(SchemaPath type, DOMDataTreeIdentifier path,
+                    ContainerNode input) {
+                final TreeNode bindingInput = input != null ? deserialize(type, input) : null;
+                final SettableFuture<RpcResult<?>> bindingResult = SettableFuture.create();
+                CompletableFuture.runAsync(() -> delegate.invoke((Input<?>) bindingInput,
+                    codec.fromYangInstanceIdentifier(path.getRootIdentifier()),
+                    new RpcCallback<Output<?>>() {
+                        public void onSuccess(Output<?> output) {
+                            bindingResult.set(RpcResultBuilder.success(output).build());
+                        }
+
+                        public void onFailure(Throwable error) {
+                            bindingResult.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION,
+                                error.getMessage()).build());
+                        }
+                    })
+                );
+                return LazyDOMActionResultFuture.create(codec, bindingResult);
+            }
+        }
     }
 }