BUG-634: Fix .so not being included in the .jar
[bgpcep.git] / tcp-md5 / jni / src / main / java / org / opendaylight / bgpcep / tcpmd5 / jni / NativeKeyAccess.java
1 /*
2  * Copyright (c) 2013 Robert Varga. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.bgpcep.tcpmd5.jni;
9
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.nio.channels.Channel;
13 import java.nio.file.Files;
14 import java.nio.file.Path;
15 import java.nio.file.StandardCopyOption;
16 import java.nio.file.attribute.PosixFilePermission;
17 import java.nio.file.attribute.PosixFilePermissions;
18 import java.util.Set;
19
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 import com.google.common.base.Preconditions;
24
25 /**
26  * Implementation of KeyAccess using Java Native Interface plugin to talk
27  * directly to the underlying operating system.
28  */
29 public final class NativeKeyAccess implements KeyAccess {
30         private static final String LIBNAME = "libtcpmd5-jni.so";
31         private static final Logger LOG = LoggerFactory.getLogger(NativeKeyAccess.class);
32         private static boolean AVAILABLE = false;
33
34         private static InputStream getLibraryStream() {
35                 return Preconditions.checkNotNull(NativeKeyAccess.class.getResourceAsStream('/' + LIBNAME),
36                                 String.format("Failed to open library resource %s", LIBNAME));
37         }
38
39         static {
40                 final Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---");
41
42                 try (final InputStream is = getLibraryStream()) {
43                         try {
44                                 final Path p = Files.createTempFile(LIBNAME, null, PosixFilePermissions.asFileAttribute(perms));
45
46                                 LOG.info("Copying {} to {}", is, p);
47
48                                 try {
49                                         Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
50
51                                         try {
52                                                 Runtime.getRuntime().load(p.toString());
53
54                                                 LOG.info("Library {} loaded", p);
55
56                                                 int rt = NarSystem.runUnitTests();
57                                                 if (rt == 0) {
58                                                         LOG.warn("Run-time initialization failed");
59                                                 } else {
60                                                         LOG.debug("Run-time found {} supported channel classes", rt);
61                                                         AVAILABLE = true;
62                                                 }
63                                         } catch (RuntimeException e) {
64                                                 LOG.error("Failed to load native library", e);
65                                         }
66                                 } catch (IOException e) {
67                                         LOG.error("Failed to extract native library", e);
68                                 } finally {
69                                         try {
70                                                 Files.deleteIfExists(p);
71                                         } catch (IOException e) {
72                                                 LOG.warn("Failed to remove temporary file", e);
73                                         }
74                                 }
75                         } catch (IOException e2) {
76                                 LOG.error("Failed to create temporary file {}", LIBNAME, e2);
77                         }
78                 } catch (IOException e1) {
79                         LOG.error("Failed to find native library {}", LIBNAME, e1);
80                 }
81         }
82
83         private static native boolean isClassSupported0(Class<?> channel);
84         private static native byte[] getChannelKey0(Channel channel) throws IOException;
85         private static native void setChannelKey0(Channel channel, byte[] key) throws IOException;
86
87         private final Channel channel;
88
89         private NativeKeyAccess(final Channel channel) {
90                 this.channel = Preconditions.checkNotNull(channel);
91         }
92
93         public static KeyAccess create(final Channel channel) {
94                 if (!AVAILABLE) {
95                         LOG.debug("Native library not available");
96                         return null;
97                 }
98
99                 if (!isClassSupported0(channel.getClass())) {
100                         LOG.debug("No support available for class {}", channel.getClass());
101                         return null;
102                 }
103
104                 return new NativeKeyAccess(channel);
105         }
106
107         public static boolean isAvailableForClass(final Class<?> clazz) {
108                 if (!AVAILABLE) {
109                         LOG.debug("Native library not available");
110                         return false;
111                 }
112
113                 if (!isClassSupported0(clazz)) {
114                         LOG.debug("No support available for class {}", clazz);
115                         return false;
116                 }
117
118                 return true;
119         }
120
121         @Override
122         public byte[] getKey() throws IOException {
123                 synchronized (channel) {
124                         return getChannelKey0(channel);
125                 }
126         }
127
128         @Override
129         public void setKey(final byte[] key) throws IOException {
130                 synchronized (channel) {
131                         setChannelKey0(channel, Preconditions.checkNotNull(key));
132                 }
133         }
134 }