1674dc9eeeeaf1cc0343b3432008a0c77efa8b12
[hc2vpp.git] /
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 io.fd.hc2vpp.common.translate.util;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20
21 import io.fd.honeycomb.translate.read.ReadFailedException;
22 import io.fd.honeycomb.translate.write.WriteFailedException;
23 import io.fd.vpp.jvpp.VppBaseCallException;
24 import io.fd.vpp.jvpp.dto.JVppReply;
25 import java.util.Optional;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.TimeUnit;
29 import java.util.concurrent.TimeoutException;
30 import javax.annotation.Nonnegative;
31 import javax.annotation.Nonnull;
32 import org.opendaylight.yangtools.yang.binding.DataObject;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * Trait providing logic for consuming reply's to jvpp api calls
39  */
40 public interface JvppReplyConsumer {
41
42     JvppReplyConsumer INSTANCE = new JvppReplyConsumer() {
43     };
44
45     /**
46      * Consumes reply for jvpp call representing any write operation
47      * Should be used in case of calls where it's not clear which write crud operation respective
48      * call represents, for ex. setRouting
49      */
50     default <R extends JVppReply<?>> R getReplyForWrite(@Nonnull Future<R> future,
51                                                             @Nonnull final InstanceIdentifier<?> replyType)
52             throws WriteFailedException {
53
54         return getReplyForWrite(future, replyType, JvppReplyTimeoutHolder.getTimeout());
55     }
56
57     /**
58      * Consumes reply for jvpp call representing any write operation
59      * Should be used in case of calls where it's not clear which write crud operation respective
60      * call represents, for ex. setRouting
61      */
62     default <R extends JVppReply<?>> R getReplyForWrite(@Nonnull Future<R> future,
63                                                             @Nonnull final InstanceIdentifier<?> replyType,
64                                                             @Nonnegative final int timeoutInSeconds)
65             throws WriteFailedException {
66         try {
67             return getReply(future, timeoutInSeconds);
68         } catch (TimeoutException e) {
69             throw new WriteTimeoutException(replyType, e);
70         } catch (VppBaseCallException e) {
71             throw new WriteFailedException(replyType, e);
72         }
73
74     }
75
76     /**
77      * Consumes reply for jvpp call representing create operation
78      */
79     default <R extends JVppReply<?>> R getReplyForCreate(@Nonnull Future<R> future,
80                                                              @Nonnull final InstanceIdentifier<?> replyType,
81                                                              @Nonnull final DataObject data)
82         throws WriteFailedException.CreateFailedException {
83         return getReplyForCreate(future, replyType, data, JvppReplyTimeoutHolder.getTimeout());
84     }
85
86     /**
87      * Consumes reply for jvpp call representing create operation
88      */
89     default <R extends JVppReply<?>> R getReplyForCreate(@Nonnull Future<R> future,
90                                                              @Nonnull final InstanceIdentifier<?> replyType,
91                                                              @Nonnull final DataObject data,
92                                                              @Nonnegative final int timeoutInSeconds)
93         throws WriteFailedException.CreateFailedException {
94         try {
95             return getReply(future, timeoutInSeconds);
96         } catch (VppBaseCallException e) {
97             throw new WriteFailedException.CreateFailedException(replyType, data, e);
98         } catch (TimeoutException e) {
99             throw new WriteFailedException.CreateFailedException(replyType, data,
100                 new WriteTimeoutException(replyType, e));
101         }
102     }
103
104     /**
105      * Consumes reply for jvpp call representing update operation
106      */
107     default <R extends JVppReply<?>> R getReplyForUpdate(@Nonnull Future<R> future,
108                                                              @Nonnull final InstanceIdentifier<?> replyType,
109                                                              @Nonnull final DataObject dataBefore,
110                                                              @Nonnull final DataObject dataAfter)
111         throws WriteFailedException.UpdateFailedException {
112         return getReplyForUpdate(future, replyType, dataBefore, dataAfter, JvppReplyTimeoutHolder.getTimeout());
113     }
114
115     /**
116      * Consumes reply for jvpp call representing update operation
117      */
118     default <R extends JVppReply<?>> R getReplyForUpdate(@Nonnull Future<R> future,
119                                                              @Nonnull final InstanceIdentifier<?> replyType,
120                                                              @Nonnull final DataObject dataBefore,
121                                                              @Nonnull final DataObject dataAfter,
122                                                              @Nonnegative final int timeoutInSeconds)
123         throws WriteFailedException.UpdateFailedException {
124         try {
125             return getReply(future, timeoutInSeconds);
126         } catch (VppBaseCallException e) {
127             throw new WriteFailedException.UpdateFailedException(replyType, dataBefore, dataAfter, e);
128         } catch (TimeoutException e) {
129             throw new WriteFailedException.UpdateFailedException(replyType, dataBefore, dataAfter,
130                 new WriteTimeoutException(replyType, e));
131         }
132     }
133
134     /**
135      * Consumes reply for jvpp call representing delete operation
136      */
137     default <R extends JVppReply<?>> R getReplyForDelete(@Nonnull Future<R> future,
138                                                              @Nonnull final InstanceIdentifier<?> replyType)
139         throws WriteFailedException.DeleteFailedException {
140         return getReplyForDelete(future, replyType, JvppReplyTimeoutHolder.getTimeout());
141     }
142
143     /**
144      * Consumes reply for jvpp call representing delete operation
145      */
146     default <R extends JVppReply<?>> R getReplyForDelete(@Nonnull Future<R> future,
147                                                              @Nonnull final InstanceIdentifier<?> replyType,
148                                                              @Nonnegative final int timeoutInSeconds)
149         throws WriteFailedException.DeleteFailedException {
150         try {
151             return getReply(future, timeoutInSeconds);
152         } catch (VppBaseCallException e) {
153             throw new WriteFailedException.DeleteFailedException(replyType, e);
154         } catch (TimeoutException e) {
155             throw new WriteFailedException.DeleteFailedException(replyType, new WriteTimeoutException(replyType, e));
156         }
157     }
158
159     default <R extends JVppReply<?>> R getReplyForRead(@Nonnull Future<R> future,
160                                                            @Nonnull final InstanceIdentifier<?> replyType)
161             throws ReadFailedException {
162         return getReplyForRead(future, replyType, JvppReplyTimeoutHolder.getTimeout());
163     }
164
165     default <R extends JVppReply<?>> R getReplyForRead(@Nonnull Future<R> future,
166                                                            @Nonnull final InstanceIdentifier<?> replyType,
167                                                            @Nonnegative final int timeoutInSeconds)
168             throws ReadFailedException {
169         try {
170             return getReply(future, timeoutInSeconds);
171         } catch (TimeoutException e) {
172             throw new ReadTimeoutException(replyType, e);
173         } catch (VppBaseCallException e) {
174             throw new ReadFailedException(replyType, e);
175         }
176     }
177
178     default <R extends JVppReply<?>> R getReply(@Nonnull Future<R> future)
179             throws TimeoutException, VppBaseCallException {
180         return getReply(future, JvppReplyTimeoutHolder.getTimeout());
181     }
182
183     default <R extends JVppReply<?>> R getReply(@Nonnull Future<R> future,
184                                                     @Nonnegative final int timeoutInSeconds)
185             throws TimeoutException, VppBaseCallException {
186         try {
187             checkArgument(timeoutInSeconds > 0, "Timeout cannot be < 0");
188             return future.get(timeoutInSeconds, TimeUnit.SECONDS);
189         } catch (InterruptedException e) {
190             Thread.currentThread().interrupt();
191             throw new IllegalStateException("Interrupted", e);
192         } catch (ExecutionException e) {
193             // Execution exception could generally contains any exception
194             // when using exceptions instead of return codes just rethrow it for processing on corresponding place
195             if (e.getCause() instanceof VppBaseCallException) {
196                 throw (VppBaseCallException) (e.getCause());
197             }
198             throw new IllegalStateException(e);
199         }
200     }
201
202     /**
203      * Wrapper for reply timeout
204      */
205     class JvppReplyTimeoutHolder {
206         private static final Logger LOG = LoggerFactory.getLogger(JvppReplyTimeoutHolder.class);
207         private static Optional<Integer> timeout = Optional.empty();
208
209         private JvppReplyTimeoutHolder() {
210             throw new UnsupportedOperationException("Utility class cannot be instantiated.");
211         }
212
213         public static void setupTimeout(@Nonnegative final int jvppTimeout) {
214             if (timeout.isPresent()) {
215                 // do not fail on reconfigure, to not disturb restarts
216                 LOG.warn("JVpp timeout already configured");
217                 return;
218             }
219             timeout = Optional.of(jvppTimeout);
220             LOG.info("Jvpp reply timeout configured to {} seconds", timeout.get());
221         }
222
223         public static int getTimeout() {
224             return timeout.orElse(5);
225         }
226     }
227 }