jaulib v1.3.0
Jau Support Library (C++, Java, ..)
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.
Definition: JNILibrary.java:47
static final Object perfSync
static final boolean DEBUG
Definition: JNILibrary.java:48
static final boolean PERF
Definition: JNILibrary.java:49
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