jaulib v1.3.6
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
JNIJarLibrary.java
Go to the documentation of this file.
1/**
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2021 Gothel Software e.K.
4 * Copyright (c) 2011 Gothel Software e.K.
5 * Copyright (c) 2011 JogAmp Community.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26package org.jau.pkg;
27
28import java.io.IOException;
29import java.net.URISyntaxException;
30import java.net.URL;
31import java.util.Arrays;
32import java.util.Locale;
33
34import org.jau.net.Uri;
35import org.jau.pkg.cache.TempJarCache;
36import org.jau.sys.JNILibrary;
37import org.jau.sys.PlatformProps;
38
39/**
40 * Static JNI Native Libraries handler including functionality for native JAR files using {@link JarUtil} and {@link TempJarCache}.
41 */
42public class JNIJarLibrary extends JNILibrary {
43 private static final String nativeJarTagPackage = "jau.nativetag"; // TODO: sync with gluegen-cpptasks-base.xml
44
45 /**
46 *
47 * @param classFromJavaJar
48 * @param classJarUri
49 * @param jarBasename jar basename w/ suffix
50 * @param nativeJarBasename native jar basename w/ suffix
51 * @return
52 * @throws IOException
53 * @throws SecurityException
54 * @throws URISyntaxException
55 */
56 private static final boolean addNativeJarLibsImpl(final Class<?> classFromJavaJar, final Uri classJarUri,
57 final Uri.Encoded jarBasename, final Uri.Encoded nativeJarBasename)
58 throws IOException, SecurityException, URISyntaxException
59 {
60 if (DEBUG) {
61 final StringBuilder msg = new StringBuilder();
62 msg.append("JNIJarLibrary: addNativeJarLibsImpl(").append(PlatformProps.NEWLINE);
63 msg.append(" classFromJavaJar = ").append(classFromJavaJar).append(PlatformProps.NEWLINE);
64 msg.append(" classJarURI = ").append(classJarUri).append(PlatformProps.NEWLINE);
65 msg.append(" jarBasename = ").append(jarBasename).append(PlatformProps.NEWLINE);
66 msg.append(" os.and.arch = ").append(PlatformProps.os_and_arch).append(PlatformProps.NEWLINE);
67 msg.append(" nativeJarBasename = ").append(nativeJarBasename).append(PlatformProps.NEWLINE);
68 msg.append(")");
69 System.err.println(msg.toString());
70 }
71 final long t0 = PERF ? System.currentTimeMillis() : 0; // 'Platform.currentTimeMillis()' not yet available!
72
73 boolean ok = false;
74
75 final Uri jarSubURI = classJarUri.getContainedUri();
76 if (null == jarSubURI) {
77 throw new IllegalArgumentException("JarSubURI is null of: "+classJarUri);
78 }
79
80 final Uri jarSubUriRoot = jarSubURI.getDirectory();
81
82 if (DEBUG) {
83 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl: initial: %s -> %s%n", jarSubURI, jarSubUriRoot);
84 }
85
86 final String nativeLibraryPath = String.format((Locale)null, "natives/%s/", PlatformProps.os_and_arch);
87 if (DEBUG) {
88 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl: nativeLibraryPath: %s%n", nativeLibraryPath);
89 }
90 {
91 // Attempt-1 a 'one slim native jar file' per 'os.and.arch' layout
92 // with native platform libraries under 'natives/os.and.arch'!
93 final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(nativeJarBasename) );
94
95 if (DEBUG) {
96 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl: module: %s -> %s%n", nativeJarBasename, nativeJarURI);
97 }
98
99 try {
100 ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath);
101 } catch(final Exception e) {
102 if(DEBUG) {
103 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
104 e.printStackTrace();
105 }
106 }
107 }
108 if (!ok) {
109 final ClassLoader cl = classFromJavaJar.getClassLoader();
110 {
111 // Attempt-2 a 'one big-fat jar file' layout, containing java classes
112 // and all native platform libraries under 'natives/os.and.arch' per platform!
113 final URL nativeLibraryURI = cl.getResource(nativeLibraryPath);
114 if (null != nativeLibraryURI) {
115 final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(jarBasename) );
116 try {
117 if( TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath) ) {
118 ok = true;
119 if (DEBUG) {
120 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl: fat: %s -> %s%n", jarBasename, nativeJarURI);
121 }
122 }
123 } catch(final Exception e) {
124 if(DEBUG) {
125 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
126 e.printStackTrace();
127 }
128 }
129 }
130 }
131 if (!ok) {
132 // Attempt-3 to find via ClassLoader and Native-Jar-Tag,
133 // assuming one slim native jar file per 'os.and.arch'
134 // and native platform libraries under 'natives/os.and.arch'!
135 final String moduleName;
136 {
137 final String packageName = classFromJavaJar.getPackage().getName();
138 final int idx = packageName.lastIndexOf('.');
139 if( 0 <= idx ) {
140 moduleName = packageName.substring(idx+1);
141 } else {
142 moduleName = packageName;
143 }
144 }
145 final String os_and_arch_dot = PlatformProps.os_and_arch.replace('-', '.');
146 final String nativeJarTagClassName = nativeJarTagPackage + "." + moduleName + "." + os_and_arch_dot + ".TAG"; // TODO: sync with gluegen-cpptasks-base.xml
147 try {
148 if(DEBUG) {
149 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl: ClassLoader/TAG: Locating module %s, os.and.arch %s: %s%n",
150 moduleName, os_and_arch_dot, nativeJarTagClassName);
151 }
152 final Uri nativeJarTagClassJarURI = JarUtil.getJarUri(nativeJarTagClassName, cl);
153 if (DEBUG) {
154 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl: ClassLoader/TAG: %s -> %s%n", nativeJarTagClassName, nativeJarTagClassJarURI);
155 }
156 ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarTagClassJarURI, nativeLibraryPath);
157 } catch (final Exception e ) {
158 if(DEBUG) {
159 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
160 e.printStackTrace();
161 }
162 }
163 }
164 }
165
166 if (DEBUG || PERF) {
167 final long tNow = System.currentTimeMillis() - t0;
168 final long tTotal, tCount;
169 synchronized(perfSync) {
170 tCount = perfCount+1;
171 tTotal = perfTotal + tNow;
172 perfTotal = tTotal;
173 perfCount = tCount;
174 }
175 final double tAvrg = tTotal / (double)tCount;
176 System.err.printf("JNIJarLibrary: addNativeJarLibsImpl.X: %s / %s -> ok: %b; duration: now %d ms, total %d ms (count %d, avrg %.3f ms)%n",
177 jarBasename, nativeJarBasename, ok, tNow, tTotal, tCount, tAvrg);
178 }
179 return ok;
180 }
181
182 /**
183 * Loads and adds a JAR file's native library to the TempJarCache.<br>
184 * The native library JAR file's URI is derived as follows:
185 * <ul>
186 * <li> [1] <code>GLProfile.class</code> -> </li>
187 * <li> [2] <code>http://lala/gluegen-rt.jar</code> -> </li>
188 * <li> [3] <code>http://lala/gluegen-rt</code> -> </li>
189 * <li> [4] <code>http://lala/gluegen-rt-natives-'os.and.arch'.jar</code> </li>
190 * </ul>
191 * Where:
192 * <ul>
193 * <li> [1] is one of <code>classesFromJavaJars</code></li>
194 * <li> [2] is it's complete URI</li>
195 * <li> [3] is it's <i>base URI</i></li>
196 * <li> [4] is the derived native JAR filename</li>
197 * </ul>
198 * <p>
199 * Generic description:
200 * <pre>
201 final Class<?>[] classesFromJavaJars = new Class<?>[] { Class1.class, Class2.class };
202 JNIJarLibrary.addNativeJarLibs(classesFromJavaJars, "-all");
203 * </pre>
204 * If <code>Class1.class</code> is contained in a JAR file which name includes <code>singleJarMarker</code>, here <i>-all</i>,
205 * implementation will attempt to resolve the native JAR file as follows:
206 * <ul>
207 * <li><i>ClassJar-all</i>.jar to <i>ClassJar-all</i>-natives-<i>os.and.arch</i>.jar</li>
208 * </ul>
209 * Otherwise the native JAR files will be resolved for each class's JAR file:
210 * <ul>
211 * <li><i>Class1Jar</i>.jar to <i>Class1Jar</i>-natives-<i>os.and.arch</i>.jar</li>
212 * <li><i>Class2Jar</i>.jar to <i>Class2Jar</i>-natives-<i>os.and.arch</i>.jar</li>
213 * </ul>
214 * </p>
215 * <p>
216 * Examples:
217 * </p>
218 * <p>
219 * JOCL:
220 * <pre>
221 // only: jocl.jar -> jocl-natives-<i>os.and.arch</i>.jar
222 addNativeJarLibs(new Class<?>[] { JOCLJNILibrary.class }, null, null );
223 * </pre>
224 * </p>
225 * <p>
226 * JOGL:
227 * <pre>
228 final ClassLoader cl = GLProfile.class.getClassLoader();
229 // jogl-all.jar -> jogl-all-natives-<i>os.and.arch</i>.jar
230 // jogl-all-noawt.jar -> jogl-all-noawt-natives-<i>os.and.arch</i>.jar
231 // jogl-all-mobile.jar -> jogl-all-mobile-natives-<i>os.and.arch</i>.jar
232 // jogl-all-android.jar -> jogl-all-android-natives-<i>os.and.arch</i>.jar
233 // nativewindow.jar -> nativewindow-natives-<i>os.and.arch</i>.jar
234 // jogl.jar -> jogl-natives-<i>os.and.arch</i>.jar
235 // newt.jar -> newt-natives-<i>os.and.arch</i>.jar (if available)
236 final String newtFactoryClassName = "com.jogamp.newt.NewtFactory";
237 final Class<?>[] classesFromJavaJars = new Class<?>[] { NWJNILibrary.class, GLProfile.class, null };
238 if( ReflectionUtil.isClassAvailable(newtFactoryClassName, cl) ) {
239 classesFromJavaJars[2] = ReflectionUtil.getClass(newtFactoryClassName, false, cl);
240 }
241 JNIJarLibrary.addNativeJarLibs(classesFromJavaJars, "-all");
242 * </pre>
243 * </p>
244 *
245 * @param classesFromJavaJars For each given Class, load the native library JAR.
246 * @param singleJarMarker Optional string marker like "-all" to identify the single 'all-in-one' JAR file
247 * after which processing of the class array shall stop.
248 *
249 * @return true if either the 'all-in-one' native JAR or all native JARs loaded successful or were loaded already,
250 * false in case of an error
251 */
252 public static boolean addNativeJarLibs(final Class<?>[] classesFromJavaJars, final String singleJarMarker) {
253 if(DEBUG) {
254 final StringBuilder msg = new StringBuilder();
255 msg.append("JNIJarLibrary: addNativeJarLibs(").append(PlatformProps.NEWLINE);
256 msg.append(" classesFromJavaJars = ").append(Arrays.asList(classesFromJavaJars)).append(PlatformProps.NEWLINE);
257 msg.append(" singleJarMarker = ").append(singleJarMarker).append(PlatformProps.NEWLINE);
258 msg.append(")");
259 System.err.println(msg.toString());
260 }
261
262 boolean ok = false;
263 if ( TempJarCache.isInitialized(true) ) {
264 ok = addNativeJarLibsWithTempJarCache(classesFromJavaJars, singleJarMarker);
265 } else if(DEBUG) {
266 System.err.println("JNIJarLibrary: addNativeJarLibs0: disabled due to uninitialized TempJarCache");
267 }
268 return ok;
269 }
270
271 private static boolean addNativeJarLibsWithTempJarCache(final Class<?>[] classesFromJavaJars, final String singleJarMarker) {
272 boolean ok;
273 int count = 0;
274 try {
275 boolean done = false;
276 ok = true;
277
278 for (int i = 0; i < classesFromJavaJars.length; ++i) {
279 final Class<?> c = classesFromJavaJars[i];
280 if (c == null) {
281 continue;
282 }
283
284 final ClassLoader cl = c.getClassLoader();
285 final Uri classJarURI = JarUtil.getJarUri(c.getName(), cl);
286 final Uri.Encoded jarName = JarUtil.getJarBasename(classJarURI);
287
288 if (jarName == null) {
289 continue;
290 }
291
292 final Uri.Encoded jarBasename = jarName.substring(0, jarName.indexOf(".jar"));
293
294 if(DEBUG) {
295 System.err.printf("JNIJarLibrary: jarBasename: %s%n", jarBasename);
296 }
297
298 /**
299 * If a jar marker was specified, and the basename contains the
300 * marker, we're done.
301 */
302
303 if (singleJarMarker != null) {
304 if (jarBasename.indexOf(singleJarMarker) >= 0) {
305 done = true;
306 }
307 }
308
309 final Uri.Encoded nativeJarBasename =
310 Uri.Encoded.cast( String.format((Locale)null, "%s-natives-%s.jar", jarBasename.get(), PlatformProps.os_and_arch) );
311
312 ok = JNIJarLibrary.addNativeJarLibsImpl(c, classJarURI, jarName, nativeJarBasename);
313 if (ok) {
314 count++;
315 }
316 if (DEBUG && done) {
317 System.err.printf("JNIJarLibrary: addNativeJarLibs0: done: %s%n", jarBasename);
318 }
319 }
320 } catch (final Exception x) {
321 System.err.printf("JNIJarLibrary: Caught %s: %s%n", x.getClass().getSimpleName(), x.getMessage());
322 if(DEBUG) {
323 x.printStackTrace();
324 }
325 ok = false;
326 }
327 if(DEBUG) {
328 System.err.printf("JNIJarLibrary: addNativeJarLibsWhenInitialized: count %d, ok %b%n", count, ok);
329 }
330 return ok;
331 }
332
333}
Immutable RFC3986 encoded string.
Definition Uri.java:301
Encoded concat(final Encoded encoded)
See String#concat(String).
Definition Uri.java:418
This class implements an immutable Uri as defined by RFC 2396.
Definition Uri.java:162
Uri getDirectory()
Returns this Uri's directory Uri.
Definition Uri.java:1599
final Encoded getEncoded()
Returns the encoded input, never null.
Definition Uri.java:1255
final Uri getContainedUri()
If this instance's schemeSpecificPart contains a Uri itself, a sub-Uri, return schemeSpecificPart + #...
Definition Uri.java:1414
Static JNI Native Libraries handler including functionality for native JAR files using JarUtil and Te...
static boolean addNativeJarLibs(final Class<?>[] classesFromJavaJars, final String singleJarMarker)
Loads and adds a JAR file's native library to the TempJarCache.
static Uri getJarFileUri(final String clazzBinName, final ClassLoader cl)
The Class's "com.jogamp.common.GlueGenVersion" Uri jar:sub_protocol:/some/path/gluegen-rt....
Definition JarUtil.java:304
static Uri getJarUri(final String clazzBinName, final ClassLoader cl)
The Class's "com.jogamp.common.GlueGenVersion" Uri jar:sub_protocol:/some/path/gluegen-rt....
Definition JarUtil.java:140
Static Jar file cache handler using an underlying instance of TempFileCache, see getTempFileCache().
static boolean isInitialized(final boolean forExecutables)
static synchronized final boolean addNativeLibs(final Class<?> certClass, final Uri jarUri, final String nativeLibraryPath)
Adds native libraries, if not yet added.
Static JNI Native Libraries handler.
static final Object perfSync
static final boolean DEBUG
static final boolean PERF
Platform Properties derived from Java properties.
static final String os_and_arch
Unique platform denominator composed as 'os_name' + '-' + 'os_arch'.
static final String NEWLINE