summaryrefslogtreecommitdiffstats
path: root/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVppRegistryImpl.java
blob: bb6730f4cae96a576cd0d242e84d7da325703a42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright (c) 2016 Cisco and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.openvpp.jvpp;

import static java.util.Objects.requireNonNull;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openvpp.jvpp.callback.ControlPingCallback;
import org.openvpp.jvpp.callback.JVppCallback;
import org.openvpp.jvpp.dto.ControlPingReply;

/**
 * Default implementation of JVppRegistry.
 */
public final class JVppRegistryImpl implements JVppRegistry, ControlPingCallback {

    private static final Logger LOG = Logger.getLogger(JVppRegistryImpl.class.getName());

    private final VppJNIConnection connection;
    private final ConcurrentMap<String, JVppCallback> pluginRegistry;
    private final ConcurrentMap<Integer, ControlPingCallback> pingCalls;

    public JVppRegistryImpl(final String clientName) throws IOException {
        connection = new VppJNIConnection(clientName);
        connection.connect();
        pluginRegistry = new ConcurrentHashMap<>();
        pingCalls = new ConcurrentHashMap<>();
    }

    @Override
    public VppConnection getConnection() {
        return connection;
    }

    @Override
    public void register(final JVpp jvpp, final JVppCallback callback) {
        requireNonNull(jvpp, "jvpp should not be null");
        requireNonNull(callback, "Callback should not be null");
        final String name = jvpp.getClass().getName();
        if (pluginRegistry.putIfAbsent(name, callback) != null) {
            throw new IllegalArgumentException(String.format("Callback for plugin %s was already registered", name));
        }
        jvpp.init(this, callback, connection.getConnectionInfo().queueAddress,
            connection.getConnectionInfo().clientIndex);
    }

    @Override
    public void unregister(final String name) {
        requireNonNull(name, "Plugin name should not be null");
        final JVppCallback previous = pluginRegistry.remove(name);
        assertPluginWasRegistered(name, previous);
    }

    @Override
    public JVppCallback get(final String name) {
        requireNonNull(name, "Plugin name should not be null");
        JVppCallback value = pluginRegistry.get(name);
        assertPluginWasRegistered(name, value);
        return value;
    }

    private native int controlPing0() throws VppInvocationException;

    @Override
    public int controlPing(final Class<? extends JVpp> clazz) throws VppInvocationException {
        connection.checkActive();
        final String name = clazz.getName();

        final ControlPingCallback callback = (ControlPingCallback) pluginRegistry.get(clazz.getName());
        assertPluginWasRegistered(name, callback);

        int context = controlPing0();
        if (context < 0) {
            throw new VppInvocationException("controlPing", context);
        }

        pingCalls.put(context, callback);
        return context;
    }


    @Override
    public void onControlPingReply(final ControlPingReply reply) {
        final ControlPingCallback callback = pingCalls.get(reply.context);
        if (callback == null) {
            LOG.log(Level.WARNING, "No callback was registered for reply id={0} ", reply.context);
            return;
        }
        // pass the reply to the callback registered by the ping caller
        callback.onControlPingReply(reply);
    }

    @Override
    public void onError(final VppCallbackException ex) {
        final int ctxId = ex.getCtxId();
        final ControlPingCallback callback = pingCalls.get(ctxId);
        if (callback == null) {
            LOG.log(Level.WARNING, "No callback was registered for reply id={0} ", ctxId);
            return;
        }
        // pass the error to the callback registered by the ping caller
        callback.onError(ex);
    }

    private static void assertPluginWasRegistered(final String name, final JVppCallback value) {
        if (value == null) {
            throw new IllegalArgumentException(String.format("Callback for plugin %s is not registered", name));
        }
    }

    @Override
    public void close() throws Exception {
        connection.close();
    }
}