docs: change code blocks from "shell" to "console"
[vpp.git] / src / vpp-api / java / jvpp-registry / io / fd / vpp / jvpp / VppJNIConnection.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 io.fd.vpp.jvpp.NativeLibraryLoader.loadLibrary;
20 import static java.lang.String.format;
21
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.nio.file.Paths;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30
31 /**
32  * JNI based representation of a management connection to VPP.
33  */
34 public final class VppJNIConnection implements VppConnection {
35     private static final Logger LOG = Logger.getLogger(VppJNIConnection.class.getName());
36     private static final String DEFAULT_SHM_PREFIX = "/vpe-api";
37
38     static {
39         final String libName = "libjvpp_registry.so";
40         try {
41             loadLibrary(libName, VppJNIConnection.class);
42         } catch (IOException e) {
43             LOG.log(Level.SEVERE, format("Can't find vpp jni library: %s", libName), e);
44             throw new ExceptionInInitializerError(e);
45         }
46     }
47
48     private ConnectionInfo connectionInfo;
49
50     private final String clientName;
51     private final String shmPrefix;
52     private volatile boolean disconnected = false;
53
54     /**
55      * Create VPPJNIConnection instance for client connecting to VPP.
56      *
57      * @param clientName client name instance to be used for communication. Single connection per clientName is
58      *                   allowed.
59      */
60     public VppJNIConnection(final String clientName) {
61         this.clientName = Objects.requireNonNull(clientName, "Null clientName");
62         this.shmPrefix = DEFAULT_SHM_PREFIX;
63     }
64
65     public VppJNIConnection(final String clientName, final String shmPrefix) {
66         this.clientName = Objects.requireNonNull(clientName, "Null clientName");
67         this.shmPrefix = Objects.requireNonNull(shmPrefix, "Null shmPrefix");
68     }
69
70     /**
71      * Guarded by VppJNIConnection.class
72      */
73     private static final Map<String, VppJNIConnection> connections = new HashMap<>();
74
75     /**
76      * Initiate VPP connection for current instance
77      *
78      * Multiple instances are allowed since this class is not a singleton (VPP allows multiple management connections).
79      *
80      * However only a single connection per clientName is allowed.
81      *
82      * @throws IOException in case the connection could not be established
83      */
84
85     @Override
86     public void connect() throws IOException {
87         _connect(shmPrefix);
88     }
89
90     private void _connect(final String shmPrefix) throws IOException {
91         Objects.requireNonNull(shmPrefix, "Shared memory prefix must be defined");
92
93         synchronized (VppJNIConnection.class) {
94             if (connections.containsKey(clientName)) {
95                 throw new IOException("Client " + clientName + " already connected");
96             }
97
98             connectionInfo = clientConnect(shmPrefix, clientName);
99             if (connectionInfo.status != 0) {
100                 throw new IOException("Connection returned error " + connectionInfo.status);
101             }
102             connections.put(clientName, this);
103         }
104     }
105
106     @Override
107     public final void checkActive() {
108         if (disconnected) {
109             throw new IllegalStateException("Disconnected client " + clientName);
110         }
111     }
112
113     @Override
114     public final synchronized void close() {
115         if (!disconnected) {
116             disconnected = true;
117             try {
118                 clientDisconnect();
119             } finally {
120                 synchronized (VppJNIConnection.class) {
121                     connections.remove(clientName);
122                 }
123             }
124         }
125     }
126
127     public ConnectionInfo getConnectionInfo() {
128         return connectionInfo;
129     }
130
131     /**
132      * VPP connection information used by plugins to reuse the connection.
133      */
134     public static final class ConnectionInfo {
135         public final long queueAddress;
136         public final int clientIndex;
137         public final int status; // FIXME throw exception instead
138         public final int pid;
139
140         public ConnectionInfo(long queueAddress, int clientIndex, int status, int pid) {
141             this.queueAddress = queueAddress;
142             this.clientIndex = clientIndex;
143             this.status = status;
144             this.pid = pid;
145         }
146     }
147
148     private static native ConnectionInfo clientConnect(String shmPrefix, String clientName);
149
150     private static native void clientDisconnect();
151
152 }