1
+ /*
2
+ * Class NativeUtils is published under the The MIT License:
3
+ *
4
+ * Copyright (c) 2012 Adam Heinrich <[email protected] >
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ package org .nethergames .proxytransport .utils ;
25
+
26
+ import java .io .*;
27
+ import java .nio .file .FileSystemNotFoundException ;
28
+ import java .nio .file .FileSystems ;
29
+ import java .nio .file .Files ;
30
+ import java .nio .file .ProviderNotFoundException ;
31
+ import java .nio .file .StandardCopyOption ;
32
+
33
+ /**
34
+ * A simple library class which helps with loading dynamic libraries stored in the
35
+ * JAR archive. These libraries usually contain implementation of some methods in
36
+ * native code (using JNI - Java Native Interface).
37
+ *
38
+ * @see <a href="http://adamheinrich.com/blog/2012/how-to-load-native-jni-library-from-jar">http://adamheinrich.com/blog/2012/how-to-load-native-jni-library-from-jar</a>
39
+ * @see <a href="https://github.com/adamheinrich/native-utils">https://github.com/adamheinrich/native-utils</a>
40
+ *
41
+ */
42
+ public class NativeUtils {
43
+
44
+ /**
45
+ * The minimum length a prefix for a file has to have according to {@link File#createTempFile(String, String)}}.
46
+ */
47
+ private static final int MIN_PREFIX_LENGTH = 3 ;
48
+ public static final String NATIVE_FOLDER_PATH_PREFIX = "nativeutils" ;
49
+
50
+ /**
51
+ * Temporary directory which will contain the DLLs.
52
+ */
53
+ private static File temporaryDir ;
54
+
55
+ /**
56
+ * Private constructor - this class will never be instanced
57
+ */
58
+ private NativeUtils () {
59
+ }
60
+
61
+ /**
62
+ * Loads library from current JAR archive
63
+ *
64
+ * The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after
65
+ * exiting.
66
+ * Method uses String as filename because the pathname is "abstract", not system-dependent.
67
+ *
68
+ * @param path The path of file inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext
69
+ * @throws IOException If temporary file creation or read/write operation fails
70
+ * @throws IllegalArgumentException If source file (param path) does not exist
71
+ * @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters
72
+ * (restriction of {@link File#createTempFile(java.lang.String, java.lang.String)}).
73
+ * @throws FileNotFoundException If the file could not be found inside the JAR.
74
+ */
75
+ public static void loadLibraryFromJar (String path ) throws IOException {
76
+
77
+ if (null == path || !path .startsWith ("/" )) {
78
+ throw new IllegalArgumentException ("The path has to be absolute (start with '/')." );
79
+ }
80
+
81
+ // Obtain filename from path
82
+ String [] parts = path .split ("/" );
83
+ String filename = (parts .length > 1 ) ? parts [parts .length - 1 ] : null ;
84
+
85
+ // Check if the filename is okay
86
+ if (filename == null || filename .length () < MIN_PREFIX_LENGTH ) {
87
+ throw new IllegalArgumentException ("The filename has to be at least 3 characters long." );
88
+ }
89
+
90
+ // Prepare temporary file
91
+ if (temporaryDir == null ) {
92
+ temporaryDir = createTempDirectory (NATIVE_FOLDER_PATH_PREFIX );
93
+ temporaryDir .deleteOnExit ();
94
+ }
95
+
96
+ File temp = new File (temporaryDir , filename );
97
+
98
+ try (InputStream is = NativeUtils .class .getResourceAsStream (path )) {
99
+ Files .copy (is , temp .toPath (), StandardCopyOption .REPLACE_EXISTING );
100
+ } catch (IOException e ) {
101
+ temp .delete ();
102
+ throw e ;
103
+ } catch (NullPointerException e ) {
104
+ temp .delete ();
105
+ throw new FileNotFoundException ("File " + path + " was not found inside JAR." );
106
+ }
107
+
108
+ try {
109
+ System .load (temp .getAbsolutePath ());
110
+ } finally {
111
+ if (isPosixCompliant ()) {
112
+ // Assume POSIX compliant file system, can be deleted after loading
113
+ temp .delete ();
114
+ } else {
115
+ // Assume non-POSIX, and don't delete until last file descriptor closed
116
+ temp .deleteOnExit ();
117
+ }
118
+ }
119
+ }
120
+
121
+ private static boolean isPosixCompliant () {
122
+ try {
123
+ return FileSystems .getDefault ()
124
+ .supportedFileAttributeViews ()
125
+ .contains ("posix" );
126
+ } catch (FileSystemNotFoundException
127
+ | ProviderNotFoundException
128
+ | SecurityException e ) {
129
+ return false ;
130
+ }
131
+ }
132
+
133
+ private static File createTempDirectory (String prefix ) throws IOException {
134
+ String tempDir = System .getProperty ("java.io.tmpdir" );
135
+ File generatedDir = new File (tempDir , prefix + System .nanoTime ());
136
+
137
+ if (!generatedDir .mkdir ())
138
+ throw new IOException ("Failed to create temp directory " + generatedDir .getName ());
139
+
140
+ return generatedDir ;
141
+ }
142
+ }
0 commit comments