2 * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import com.google.common.util.concurrent.FluentFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.lang.reflect.InvocationHandler;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.Proxy;
21 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
22 import org.opendaylight.mdsal.binding.javav2.dom.codec.serialized.LazySerializedContainerNode;
23 import org.opendaylight.mdsal.binding.javav2.spec.base.Action;
24 import org.opendaylight.mdsal.binding.javav2.spec.base.Input;
25 import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
26 import org.opendaylight.mdsal.binding.javav2.spec.base.Output;
27 import org.opendaylight.mdsal.binding.javav2.spec.base.RpcCallback;
28 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.mdsal.dom.api.DOMActionResult;
31 import org.opendaylight.mdsal.dom.api.DOMActionService;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
33 import org.opendaylight.yangtools.yang.common.RpcResult;
34 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
35 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
38 class ActionServiceAdapter implements InvocationHandler {
40 private final Class<? extends Action<? extends TreeNode, ?, ?, ?>> type;
41 private final BindingToNormalizedNodeCodec codec;
42 private final DOMActionService delegate;
43 private final Action<? extends TreeNode, ?, ?, ?> proxy;
44 private final SchemaPath path;
46 ActionServiceAdapter(final Class<? extends Action<? extends TreeNode, ?, ?, ?>> type,
47 final BindingToNormalizedNodeCodec codec, final DOMActionService domService) {
48 this.type = requireNonNull(type);
49 this.codec = requireNonNull(codec);
50 this.delegate = requireNonNull(domService);
51 this.path = getCodec().getActionPath(type);
52 proxy = (Action<? extends TreeNode, ?, ?, ?>) Proxy.newProxyInstance(type.getClassLoader(),
53 new Class[] { type }, this);
56 public BindingToNormalizedNodeCodec getCodec() {
60 public DOMActionService getDelegate() {
64 Action<? extends TreeNode, ?, ?, ?> getProxy() {
68 public Class<? extends Action<? extends TreeNode, ?, ?, ?>> getType() {
72 public SchemaPath getPath() {
77 @SuppressWarnings("checkstyle:hiddenField")
78 public Object invoke(final Object proxy, final Method method, final Object[] args) {
80 switch (method.getName()) {
82 if (args.length == 1) {
83 return proxy == args[0];
87 if (args.length == 0) {
88 return System.identityHashCode(proxy);
92 if (args.length == 0) {
93 return type.getName() + "$Adapter{delegate=" + getDelegate() + "}";
97 if (args.length == 3) {
98 final Input<?> input = (Input<?>) requireNonNull(args[0]);
99 final InstanceIdentifier<?> path = (InstanceIdentifier<?>) requireNonNull(args[1]);
100 final RpcCallback<Output> callback = (RpcCallback<Output>) requireNonNull(args[2]);
102 final FluentFuture<? extends DOMActionResult> future = getDelegate().invokeAction(getPath(),
103 new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, getCodec().toNormalized(path)),
104 (ContainerNode) LazySerializedContainerNode.create(getPath(), (TreeNode) input,
105 getCodec().getCodecRegistry()));
106 //FIXME:this part is ugly, how to bridge FluentFuture and RpcCallback better?
107 // Invocation returned a future we know about -- return that future instead
108 if (future instanceof LazyDOMActionResultFuture) {
109 ListenableFuture<RpcResult<?>> bindingFuture =
110 ((LazyDOMActionResultFuture) future).getBindingFuture();
111 Futures.addCallback(bindingFuture, new FutureCallback<RpcResult<?>>() {
114 public void onSuccess(final RpcResult<?> result) {
115 if (result.isSuccessful()) {
116 callback.onSuccess((Output) result.getResult());
118 //FIXME: It's not suitable to do this way here. It's better for
119 // 'onFailure' to accept Collection<RpcError> as input.
120 result.getErrors().forEach(e -> callback.onFailure(e.getCause()));
125 public void onFailure(final Throwable throwable) {
126 callback.onFailure(throwable);
128 }, MoreExecutors.directExecutor());
130 Futures.addCallback(future, new FutureCallback<DOMActionResult>() {
133 public void onSuccess(final DOMActionResult result) {
134 if (result.getErrors().isEmpty()) {
135 callback.onSuccess((Output) getCodec().fromNormalizedNodeOperationData(getPath(),
136 result.getOutput().get()));
138 result.getErrors().forEach(e -> callback.onFailure(e.getCause()));
143 public void onFailure(final Throwable throwable) {
144 callback.onFailure(throwable);
146 }, MoreExecutors.directExecutor());
154 throw new UnsupportedOperationException("Method " + method.toString() + "is unsupported.");