Bug 2364: Migrated Binding MD-SAL to not use composites nodes
[mdsal.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / md / sal / binding / impl / BindingDOMRpcServiceAdapter.java
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMRpcServiceAdapter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMRpcServiceAdapter.java
new file mode 100644 (file)
index 0000000..9694bc9
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2015 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.controller.md.sal.binding.impl;
+
+import com.google.common.base.Function;
+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 com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.lang.reflect.Method;
+import java.util.Set;
+import org.opendaylight.controller.md.sal.binding.impl.BindingDOMAdapterBuilder.Factory;
+import org.opendaylight.controller.md.sal.binding.impl.RpcServiceAdapter.InvocationDelegate;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.api.DOMService;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+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;
+
+public class BindingDOMRpcServiceAdapter implements RpcConsumerRegistry, InvocationDelegate {
+
+    protected static final Factory<RpcConsumerRegistry> BUILDER_FACTORY = new Factory<RpcConsumerRegistry>() {
+
+        @Override
+        public BindingDOMAdapterBuilder<RpcConsumerRegistry> newBuilder() {
+            return new Builder();
+        }
+
+    };
+
+    private final LoadingCache<Class<? extends RpcService>, RpcServiceAdapter> proxies = CacheBuilder.newBuilder()
+            .weakKeys()
+            .build(new CacheLoader<Class<? extends RpcService>, RpcServiceAdapter>() {
+
+                @Override
+                public RpcServiceAdapter load(final Class<? extends RpcService> key) throws Exception {
+                    return createProxy(key);
+                }
+
+            });
+
+    private final DOMRpcService domService;
+    private final BindingToNormalizedNodeCodec codec;
+
+    public BindingDOMRpcServiceAdapter(final DOMRpcService domService, final BindingToNormalizedNodeCodec codec) {
+        super();
+        this.domService = domService;
+        this.codec = codec;
+    }
+
+    @Override
+    public <T extends RpcService> T getRpcService(final Class<T> rpcService) {
+        Preconditions.checkArgument(rpcService != null, "Rpc Service needs to be specied.");
+        @SuppressWarnings("unchecked")
+        final
+        T proxy = (T) proxies.getUnchecked(rpcService).getProxy();
+        return proxy;
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<?>> invoke(final SchemaPath rpc, final DataObject input) {
+        final CheckedFuture<DOMRpcResult, DOMRpcException> domFuture = domService.invokeRpc(rpc, serialize(rpc,input));
+        return transformFuture(rpc,domFuture,codec.getCodecFactory());
+    }
+
+    private RpcServiceAdapter createProxy(final Class<? extends RpcService> key) {
+        Preconditions.checkArgument(BindingReflections.isBindingClass(key));
+        Preconditions.checkArgument(key.isInterface(), "Supplied RPC service type must be interface.");
+        final ImmutableMap<Method, SchemaPath> rpcNames = codec.getRpcMethodToSchemaPath(key);
+        return new RpcServiceAdapter(key, rpcNames, this);
+    }
+
+    private NormalizedNode<?, ?> serialize(final SchemaPath rpc,final DataObject input) {
+        if(input == null) {
+            return null;
+        }
+        final QName rpcInputIdentifier = QName.create(rpc.getLastComponent(),"input");
+        return new LazySerializedContainerNode(rpcInputIdentifier, input, codec.getCodecFactory());
+    }
+
+    private static ListenableFuture<RpcResult<?>> transformFuture(final SchemaPath rpc,final ListenableFuture<DOMRpcResult> domFuture, final BindingNormalizedNodeCodecRegistry codec) {
+        return Futures.transform(domFuture, new Function<DOMRpcResult, RpcResult<?>>() {
+            @Override
+            public RpcResult<?> apply(final DOMRpcResult input) {
+                if(input instanceof LazySerializedDOMRpcResult) {
+                    return ((LazySerializedDOMRpcResult) input).bidningRpcResult();
+                }
+                final NormalizedNode<?, ?> domData = input.getResult();
+                final DataObject bindingResult;
+                if(domData != null) {
+                    final SchemaPath rpcOutput = rpc.createChild(QName.create(rpc.getLastComponent(),"output"));
+                    bindingResult = codec.fromNormalizedNodeRpcData(rpcOutput, (ContainerNode) domData);
+                } else {
+                    bindingResult = null;
+                }
+                return RpcResult.class.cast(RpcResultBuilder.success(bindingResult).build());
+            }
+        });
+    }
+
+    private static final class Builder extends BindingDOMAdapterBuilder<RpcConsumerRegistry> {
+
+        @Override
+        protected RpcConsumerRegistry createInstance(final BindingToNormalizedNodeCodec codec,
+                final ClassToInstanceMap<DOMService> delegates) {
+            final DOMRpcService domRpc  = delegates.getInstance(DOMRpcService.class);
+            return new BindingDOMRpcServiceAdapter(domRpc  , codec);
+        }
+
+        @Override
+        public Set<? extends Class<? extends DOMService>> getRequiredDelegates() {
+            return ImmutableSet.of(DOMRpcService.class);
+        }
+
+    }
+
+}