01578ce03264b2c223ff641a226817072ff61ea4
[vpp.git] / vpp-api / java / jvpp-registry / io / fd / vpp / jvpp / JVppRegistryImpl.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 io.fd.vpp.jvpp;
18
19 import static java.util.Objects.requireNonNull;
20
21 import io.fd.vpp.jvpp.callback.ControlPingCallback;
22 import io.fd.vpp.jvpp.callback.JVppCallback;
23 import io.fd.vpp.jvpp.dto.ControlPingReply;
24 import java.io.IOException;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.ConcurrentMap;
29 import java.util.logging.Level;
30 import java.util.logging.Logger;
31
32 /**
33  * Default implementation of JVppRegistry.
34  */
35 public final class JVppRegistryImpl implements JVppRegistry, ControlPingCallback {
36
37     private static final Logger LOG = Logger.getLogger(JVppRegistryImpl.class.getName());
38
39     private final VppJNIConnection connection;
40     private final Map<String, JVppCallback> pluginRegistry;
41     private final ConcurrentMap<Integer, ControlPingCallback> pingCalls;
42
43     public JVppRegistryImpl(final String clientName) throws IOException {
44         connection = new VppJNIConnection(clientName);
45         connection.connect();
46         pluginRegistry = new HashMap<>();
47         pingCalls = new ConcurrentHashMap<>();
48     }
49
50     @Override
51     public VppConnection getConnection() {
52         return connection;
53     }
54
55     @Override
56     public synchronized void register(final JVpp jvpp, final JVppCallback callback) {
57         requireNonNull(jvpp, "jvpp should not be null");
58         requireNonNull(callback, "Callback should not be null");
59         final String name = jvpp.getClass().getName();
60         if (pluginRegistry.containsKey(name)) {
61             throw new IllegalArgumentException(
62                 String.format("Callback for plugin %s was already registered", name));
63         }
64         jvpp.init(this, callback, connection.getConnectionInfo().queueAddress,
65             connection.getConnectionInfo().clientIndex);
66         pluginRegistry.put(name, callback);
67     }
68
69     @Override
70     public synchronized void unregister(final String name) {
71         requireNonNull(name, "Plugin name should not be null");
72         final JVppCallback previous = pluginRegistry.remove(name);
73         assertPluginWasRegistered(name, previous);
74     }
75
76     @Override
77     public synchronized JVppCallback get(final String name) {
78         requireNonNull(name, "Plugin name should not be null");
79         JVppCallback value = pluginRegistry.get(name);
80         assertPluginWasRegistered(name, value);
81         return value;
82     }
83
84     private native int controlPing0() throws VppInvocationException;
85
86     @Override
87     public synchronized int controlPing(final Class<? extends JVpp> clazz) throws VppInvocationException {
88         connection.checkActive();
89         final String name = clazz.getName();
90
91         final ControlPingCallback callback = (ControlPingCallback) pluginRegistry.get(clazz.getName());
92         assertPluginWasRegistered(name, callback);
93
94         int context = controlPing0();
95         if (context < 0) {
96             throw new VppInvocationException("controlPing", context);
97         }
98
99         pingCalls.put(context, callback);
100         return context;
101     }
102
103     @Override
104     public void onControlPingReply(final ControlPingReply reply) {
105         final ControlPingCallback callback = pingCalls.get(reply.context);
106         if (callback == null) {
107             LOG.log(Level.WARNING, "No callback was registered for reply id={0} ", reply.context);
108             return;
109         }
110         // pass the reply to the callback registered by the ping caller
111         callback.onControlPingReply(reply);
112     }
113
114     @Override
115     public void onError(final VppCallbackException ex) {
116         final int ctxId = ex.getCtxId();
117         final ControlPingCallback callback = pingCalls.get(ctxId);
118         if (callback == null) {
119             LOG.log(Level.WARNING, "No callback was registered for reply id={0} ", ctxId);
120             return;
121         }
122         // pass the error to the callback registered by the ping caller
123         callback.onError(ex);
124     }
125
126     private static void assertPluginWasRegistered(final String name, final JVppCallback value) {
127         if (value == null) {
128             throw new IllegalArgumentException(String.format("Callback for plugin %s is not registered", name));
129         }
130     }
131
132     @Override
133     public void close() throws Exception {
134         connection.close();
135     }
136 }