VPP-330 Track pending map-requests with a fifo
[vpp.git] / vpp-api / java / jvpp / org / openvpp / jvpp / future / FutureJVppInvokerFacade.java
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openvpp.jvpp.future;
18
19
20 import org.openvpp.jvpp.JVpp;
21 import org.openvpp.jvpp.VppInvocationException;
22 import org.openvpp.jvpp.dto.*;
23
24 import java.util.Map;
25 import java.util.Objects;
26 import java.util.concurrent.CompletableFuture;
27 import java.util.concurrent.CompletionStage;
28 import org.openvpp.jvpp.notification.NotificationRegistryProviderContext;
29
30 /**
31 * Future facade on top of JVpp
32 */
33 public class FutureJVppInvokerFacade extends NotificationRegistryProviderContext implements FutureJVppInvoker {
34
35     private final JVpp jvpp;
36
37     /**
38      * Guarded by self
39      */
40     private final Map<Integer, CompletableFuture<? extends JVppReply<?>>> requests;
41
42     public FutureJVppInvokerFacade(final JVpp jvpp,
43                                    final Map<Integer, CompletableFuture<? extends JVppReply<?>>> requestMap) {
44         this.jvpp =  Objects.requireNonNull(jvpp, "Null jvpp");
45         // Request map represents the shared state between this facade and it's callback
46         // where facade puts futures in and callback completes + removes them
47         // TODO what if the call never completes ?
48         this.requests = Objects.requireNonNull(requestMap, "Null requestMap");
49     }
50
51     protected final Map<Integer, CompletableFuture<? extends JVppReply<?>>> getRequests() {
52         return this.requests;
53     }
54
55     // TODO use Optional in Future, java8
56
57     @Override
58     @SuppressWarnings("unchecked")
59     public <REQ extends JVppRequest, REPLY extends JVppReply<REQ>> CompletionStage<REPLY> send(REQ req) {
60         synchronized(requests) {
61             try {
62                 final CompletableFuture<REPLY> replyCompletableFuture;
63                 final int contextId = jvpp.send(req);
64
65                 if(req instanceof JVppDump) {
66                     replyCompletableFuture = (CompletableFuture<REPLY>) new CompletableDumpFuture<>(contextId);
67                 } else {
68                     replyCompletableFuture = new CompletableFuture<>();
69                 }
70
71                 requests.put(contextId, replyCompletableFuture);
72                 if(req instanceof JVppDump) {
73                     requests.put(jvpp.send(new ControlPing()), replyCompletableFuture);
74                 }
75                 return replyCompletableFuture;
76             } catch (VppInvocationException ex) {
77                 final CompletableFuture<REPLY> replyCompletableFuture = new CompletableFuture<>();
78                 replyCompletableFuture.completeExceptionally(ex);
79                 return replyCompletableFuture;
80             }
81         }
82     }
83
84     static final class CompletableDumpFuture<T extends JVppReplyDump<?, ?>> extends CompletableFuture<T> {
85         // The reason why this is not final is the instantiation of ReplyDump DTOs
86         // Their instantiation must be generated, so currently the DTOs are created in callback and set when first dump reponses
87         // is handled in the callback.
88         private T replyDump;
89         private final long contextId;
90
91         CompletableDumpFuture(final long contextId) {
92             this.contextId = contextId;
93         }
94
95         long getContextId() {
96             return contextId;
97         }
98
99         T getReplyDump() {
100             return replyDump;
101         }
102
103         void setReplyDump(final T replyDump) {
104             this.replyDump = replyDump;
105         }
106     }
107
108     @Override
109     public void close() throws Exception {
110         // NOOP
111     }
112 }