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