Change DOM invokeRpc to FluentFuture
[mdsal.git] / binding2 / mdsal-binding2-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / javav2 / dom / adapter / impl / operation / LazyDOMOperationResultFuture.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.AbstractFuture;
13 import com.google.common.util.concurrent.FluentFuture;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.Executor;
17 import java.util.concurrent.TimeUnit;
18 import java.util.concurrent.TimeoutException;
19 import javax.annotation.Nonnull;
20 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
21 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
22 import org.opendaylight.mdsal.dom.api.DOMRpcException;
23 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
24 import org.opendaylight.mdsal.dom.api.DefaultDOMRpcException;
25 import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
26 import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
27 import org.opendaylight.yangtools.yang.binding.DataContainer;
28 import org.opendaylight.yangtools.yang.common.RpcResult;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30
31 /**
32  * DOM operation result from Binding.
33  */
34 @Beta
35 final class LazyDOMOperationResultFuture extends AbstractFuture<DOMRpcResult> {
36     private static final ExceptionMapper<DOMRpcException> DOM_RPC_EX_MAPPER =
37             new ExceptionMapper<DOMRpcException>("rpc", DOMRpcException.class) {
38         @Override
39         protected DOMRpcException newWithCause(String message, Throwable cause) {
40             return cause instanceof DOMRpcException ? (DOMRpcException)cause
41                     : new DefaultDOMRpcException("RPC failed", cause);
42         }
43     };
44
45     private final ListenableFuture<RpcResult<?>> bindingFuture;
46     private final BindingNormalizedNodeCodecRegistry codec;
47     private volatile DOMRpcResult result;
48
49     private LazyDOMOperationResultFuture(final ListenableFuture<RpcResult<?>> delegate,
50             final BindingNormalizedNodeCodecRegistry codec) {
51         this.bindingFuture = Preconditions.checkNotNull(delegate, "delegate");
52         this.codec = Preconditions.checkNotNull(codec, "codec");
53     }
54
55     static FluentFuture<DOMRpcResult> create(final BindingNormalizedNodeCodecRegistry codec,
56             final ListenableFuture<RpcResult<?>> bindingResult) {
57         return new LazyDOMOperationResultFuture(bindingResult, codec);
58     }
59
60     ListenableFuture<RpcResult<?>> getBindingFuture() {
61         return bindingFuture;
62     }
63
64     @Override
65     public boolean cancel(final boolean mayInterruptIfRunning) {
66         return bindingFuture.cancel(mayInterruptIfRunning);
67     }
68
69     @Override
70     public void addListener(@Nonnull final Runnable listener, @Nonnull final Executor executor) {
71         bindingFuture.addListener(listener, executor);
72     }
73
74     @Override
75     public DOMRpcResult get() throws InterruptedException, ExecutionException {
76         if (result != null) {
77             return result;
78         }
79
80         try {
81             return transformIfNecessary(bindingFuture.get());
82         } catch (ExecutionException e) {
83             throw new ExecutionException(e.getMessage(), DOM_RPC_EX_MAPPER.apply(e));
84         }
85     }
86
87     @Override
88     public DOMRpcResult get(@Nonnull final long timeout, final TimeUnit unit)
89             throws InterruptedException, ExecutionException, TimeoutException {
90         if (result != null) {
91             return result;
92         }
93
94         try {
95             return transformIfNecessary(bindingFuture.get(timeout, unit));
96         } catch (ExecutionException e) {
97             throw new ExecutionException(e.getMessage(), DOM_RPC_EX_MAPPER.apply(e));
98         }
99     }
100
101     @Override
102     public boolean isCancelled() {
103         return bindingFuture.isCancelled();
104     }
105
106     @Override
107     public boolean isDone() {
108         return bindingFuture.isDone();
109     }
110
111     private synchronized DOMRpcResult transformIfNecessary(final RpcResult<?> input) {
112         if (result == null) {
113             result = transform(input);
114         }
115         return result;
116     }
117
118     private DOMRpcResult transform(final RpcResult<?> input) {
119         if (input.isSuccessful()) {
120             final Object inputData = input.getResult();
121             if (inputData instanceof DataContainer) {
122                 return new DefaultDOMRpcResult(codec.toNormalizedNodeOperationData((TreeNode) inputData));
123             } else {
124                 return new DefaultDOMRpcResult((NormalizedNode<?, ?>) null);
125             }
126         }
127         return new DefaultDOMRpcResult(input.getErrors());
128     }
129
130 }