GlueGen v2.6.0-rc-20250712
GlueGen, Native Binding Generator for Java™ (public API).
DynamicLibraryBundle.java
Go to the documentation of this file.
1/**
2 * Copyright 2010-2023 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.common.os;
30
31import java.util.ArrayList;
32import java.util.Arrays;
33import java.util.HashSet;
34import java.util.List;
35
36import com.jogamp.common.jvm.JNILibLoaderBase;
37import com.jogamp.common.util.RunnableExecutor;
38
39/**
40 * Provides bundling of:<br>
41 * <ul>
42 * <li>The to-be-glued native library, eg OpenGL32.dll. From here on this is referred as the Tool.</li>
43 * <li>The JNI glue-code native library, eg jogl_desktop.dll. From here on this is referred as the Glue</li>
44 * </ul>
45 * <p>
46 * An {@link DynamicLibraryBundleInfo} instance is being passed in the constructor,
47 * providing the required information about the tool and glue libraries.
48 * The ClassLoader of it's implementation is also being used to help locating the native libraries.
49 * </p>
50 * An instance provides a complete {@link com.jogamp.common.os.DynamicLookupHelper}
51 * to {@link com.jogamp.gluegen.runtime.ProcAddressTable#reset(com.jogamp.common.os.DynamicLookupHelper) reset}
52 * the {@link com.jogamp.gluegen.runtime.ProcAddressTable}.<br>
53 * At construction, it:
54 * <ul>
55 * <li> loads the Tool native library via
56 * {@link com.jogamp.common.os.NativeLibrary#open(java.lang.String, java.lang.ClassLoader, boolean) NativeLibrary's open method}</li>
57 * <li> loads the {@link com.jogamp.common.jvm.JNILibLoaderBase#loadLibrary(java.lang.String, java.lang.String[], boolean, ClassLoader) Glue native library}</li>
58 * <li> resolves the Tool's {@link com.jogamp.common.os.DynamicLibraryBundleInfo#getToolGetProcAddressFuncNameList() GetProcAddress}. (optional)</li>
59 * </ul>
60 */
62 private final DynamicLibraryBundleInfo info;
63
64 private final List<List<String>> toolLibNames;
65 protected final List<NativeLibrary> toolLibraries;
66 private final List<String> toolLibSymbolNames;
67 private final List<String> glueLibNames;
68 private final boolean[] toolLibLoaded;
69 private final DynamicLinker dynLinkGlobal;
70
71 private int toolLibLoadedNumber;
72
73 private final boolean[] glueLibLoaded;
74 private int glueLibLoadedNumber;
75
76 private long toolGetProcAddressHandle;
77 private boolean toolGetProcAddressComplete;
78 private HashSet<String> toolGetProcAddressFuncNameSet;
79 private final List<String> toolGetProcAddressFuncNameList;
80
81 /** Returns an AWT-EDT {@link RunnableExecutor} implementation if AWT is available, otherwise {@link RunnableExecutor#currentThreadExecutor}. */
84 }
85
86 /**
87 * Instantiates and loads all {@link NativeLibrary}s incl. JNI libraries.
88 * <p>
89 * The ClassLoader of the {@link DynamicLibraryBundleInfo} implementation class
90 * is being used to help locating the native libraries.
91 * </p>
92 */
94 if(null==info) {
95 throw new RuntimeException("Null DynamicLibraryBundleInfo");
96 }
97 this.info = info;
98 if(DEBUG) {
99 System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.init start with: "+info.getClass().getName());
100 }
101 toolLibNames = info.getToolLibNames();
102 toolLibraries = new ArrayList<NativeLibrary>(toolLibNames.size());
103 toolLibSymbolNames = info.getSymbolForToolLibPath();
104 glueLibNames = info.getGlueLibNames();
105 toolLibLoaded = new boolean[toolLibNames.size()];
106 if(DEBUG) {
107 if( toolLibNames.size() == 0 ) {
108 System.err.println("No Tool native library names given");
109 }
110
111 if( glueLibNames.size() == 0 ) {
112 System.err.println("No Glue native library names given");
113 }
114 }
115
116 for(int i=toolLibNames.size()-1; i>=0; i--) {
117 toolLibLoaded[i] = false;
118 }
119 glueLibLoaded = new boolean[glueLibNames.size()];
120 for(int i=glueLibNames.size()-1; i>=0; i--) {
121 glueLibLoaded[i] = false;
122 }
123
124 {
125 final DynamicLinker[] _dynLinkGlobal = { null };
126 info.getLibLoaderExecutor().invoke(true, new Runnable() {
127 @Override
128 public void run() {
129 _dynLinkGlobal[0] = loadLibraries();
130 } } ) ;
131 dynLinkGlobal = _dynLinkGlobal[0];
132 }
133
134 toolGetProcAddressFuncNameList = info.getToolGetProcAddressFuncNameList();
135 if( null != toolGetProcAddressFuncNameList ) {
136 toolGetProcAddressFuncNameSet = new HashSet<String>(toolGetProcAddressFuncNameList);
137 toolGetProcAddressHandle = retrieveToolGetProcAddressHandle();
138 toolGetProcAddressComplete = 0 != toolGetProcAddressHandle;
139 } else {
140 toolGetProcAddressFuncNameSet = new HashSet<String>();
141 toolGetProcAddressHandle = 0;
142 toolGetProcAddressComplete = true;
143 }
144 if(DEBUG) {
145 System.err.println("DynamicLibraryBundle.init Summary: "+info.getClass().getName());
146 System.err.println(" toolGetProcAddressFuncNameList: "+toolGetProcAddressFuncNameList+", complete: "+toolGetProcAddressComplete+", 0x"+Long.toHexString(toolGetProcAddressHandle));
147 System.err.println(" Tool Lib Names : "+toolLibNames);
148 System.err.println(" Tool Lib Symbol: "+toolLibSymbolNames);
149 System.err.println(" Tool Lib Loaded: "+getToolLibLoadedNumber()+"/"+getToolLibNumber()+" "+Arrays.toString(toolLibLoaded)+", complete "+isToolLibComplete());
150 System.err.println(" Tool Libraries : "+toolLibraries);
151 System.err.println(" Glue Lib Names : "+glueLibNames);
152 System.err.println(" Glue Lib Loaded: "+getGlueLibLoadedNumber()+"/"+getGlueLibNumber()+" "+Arrays.toString(glueLibLoaded)+", complete "+isGlueLibComplete());
153 System.err.println(" All Complete: "+isLibComplete());
154 System.err.println(" LibLoaderExecutor: "+info.getLibLoaderExecutor().getClass().getName());
155 }
156 }
157
158 /** Unload all {@link NativeLibrary}s, and remove all references. */
159 public final void destroy() {
160 if(DEBUG) {
161 System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.destroy() START: "+info.getClass().getName());
162 }
163 toolGetProcAddressFuncNameSet = null;
164 toolGetProcAddressHandle = 0;
165 toolGetProcAddressComplete = false;
166 for(int i = 0; i<toolLibraries.size(); i++) {
167 final NativeLibrary lib = toolLibraries.get(i);
168 if( null != lib ) {
169 lib.close();
170 }
171 }
172 toolLibraries.clear();
173 toolLibNames.clear();
174 glueLibNames.clear();
175 if(DEBUG) {
176 System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.destroy() END: "+info.getClass().getName());
177 }
178 }
179
180 public final boolean isLibComplete() {
182 }
183
184 public final int getToolLibNumber() {
185 return toolLibNames.size();
186 }
187
188 public final int getToolLibLoadedNumber() {
189 return toolLibLoadedNumber;
190 }
191
192 /**
193 * @return true if all tool libraries are loaded,
194 * otherwise false.
195 *
196 * @see DynamicLibraryBundleInfo#getToolLibNames()
197 */
198 public final boolean isToolLibComplete() {
199 final int toolLibNumber = getToolLibNumber();
200 return toolGetProcAddressComplete &&
201 ( 0 == toolLibNumber || null != dynLinkGlobal ) &&
202 toolLibNumber == getToolLibLoadedNumber();
203 }
204
205 public final boolean isToolLibLoaded() {
206 return 0 < toolLibLoadedNumber;
207 }
208
209 public final boolean isToolLibLoaded(final int i) {
210 if(0 <= i && i < toolLibLoaded.length) {
211 return toolLibLoaded[i];
212 }
213 return false;
214 }
215
216 @Override
217 public final boolean isOpen() { return isToolLibLoaded(); }
218
219 /**
220 * Returns list of {@link NativeLibrary}s for each {@link DynamicLibraryBundleInfo#getToolLibNames()} in the same size and order.
221 * May contain elements with {@code null} for not loaded libs.
222 */
223 public final List<NativeLibrary> getToolLibraries() { return toolLibraries; }
224
225 /**
226 * Returns {@link NativeLibrary} at given index of all {@link DynamicLibraryBundleInfo#getToolLibNames()} in the same size and order.
227 * May return {@code null} if not loaded.
228 */
229 public final NativeLibrary getToolLibrary(final int i) {
230 if(0 <= i && i < toolLibraries.size()) {
231 return toolLibraries.get(i);
232 }
233 return null;
234 }
235
236 public final int getGlueLibNumber() {
237 return glueLibNames.size();
238 }
239
240 public final int getGlueLibLoadedNumber() {
241 return glueLibLoadedNumber;
242 }
243
244 /**
245 * @return true if the last entry has been loaded,
246 * while ignoring the preload dependencies.
247 * Otherwise false.
248 *
249 * @see DynamicLibraryBundleInfo#getGlueLibNames()
250 */
251 public final boolean isGlueLibComplete() {
252 return 0 == getGlueLibNumber() || isGlueLibLoaded(getGlueLibNumber() - 1);
253 }
254
255 public final boolean isGlueLibLoaded(final int i) {
256 if(0 <= i && i < glueLibLoaded.length) {
257 return glueLibLoaded[i];
258 }
259 return false;
260 }
261
262 public final DynamicLibraryBundleInfo getBundleInfo() { return info; }
263
264 public final long getToolGetProcAddressHandle() { return toolGetProcAddressHandle; }
265
266 protected final long retrieveToolGetProcAddressHandle() throws SecurityException {
267 if(!isToolLibLoaded()) {
268 return 0;
269 }
270 long aptr = 0;
271 for (int i=0; i < toolGetProcAddressFuncNameList.size(); i++) {
272 final String name = toolGetProcAddressFuncNameList.get(i);
273 aptr = dynamicLookupFunctionOnLibs(name);
274 if(DEBUG) {
275 System.err.println("getToolGetProcAddressHandle: "+name+" -> 0x"+Long.toHexString(aptr));
276 }
277 }
278 return aptr;
279 }
280
281 protected static final NativeLibrary loadFirstAvailable(final List<String> libNames,
282 final boolean searchOSSystemPath,
283 final boolean searchSystemPathFirst,
284 final ClassLoader loader, final boolean global, final String symbolName) throws SecurityException {
285 for (int i=0; i < libNames.size(); i++) {
286 final NativeLibrary lib = NativeLibrary.open(libNames.get(i), searchOSSystemPath, searchSystemPathFirst, loader, global, symbolName);
287 if (lib != null) {
288 return lib;
289 }
290 }
291 return null;
292 }
293
294 final DynamicLinker loadLibraries() throws SecurityException {
295 int i;
296 toolLibLoadedNumber = 0;
297 final ClassLoader cl = info.getClass().getClassLoader();
298 NativeLibrary lib = null;
299 DynamicLinker dynLinkGlobal = null;
300
301 for (i=0; i < toolLibNames.size(); i++) {
302 final List<String> libNames = toolLibNames.get(i);
303 final String symbolName = i < toolLibSymbolNames.size() ? toolLibSymbolNames.get(i) : null;
304 if( null != libNames && libNames.size() > 0 ) {
305 lib = loadFirstAvailable(libNames,
308 cl, info.shallLinkGlobal(), symbolName);
309 toolLibraries.add(lib);
310 if ( null == lib ) {
311 if(DEBUG) {
312 System.err.println("Unable to load any Tool library of: "+libNames);
313 }
314 } else {
315 if( null == dynLinkGlobal ) {
316 dynLinkGlobal = lib.dynamicLinker();
317 }
318 toolLibLoaded[i] = true;
319 toolLibLoadedNumber++;
320 if(DEBUG) {
321 System.err.println("Loaded Tool library: "+lib);
322 }
323 }
324 } else {
325 toolLibraries.add(null); // same size and order as toolLibNames!
326 }
327 }
328 if( toolLibNames.size() > 0 && !isToolLibLoaded() ) {
329 if(DEBUG) {
330 System.err.println("No Tool libraries loaded");
331 }
332 return dynLinkGlobal;
333 }
334
335 glueLibLoadedNumber = 0;
336 for (i=0; i < glueLibNames.size(); i++) {
337 final String libName = glueLibNames.get(i);
338 final boolean ignoreError = true;
339 boolean res;
340 try {
341 res = GlueJNILibLoader.loadLibrary(libName, ignoreError, cl);
342 if(DEBUG && !res) {
343 System.err.println("Info: Could not load JNI/Glue library: "+libName);
344 }
345 } catch (final UnsatisfiedLinkError e) {
346 res = false;
347 if(DEBUG) {
348 System.err.println("Unable to load JNI/Glue library: "+libName);
349 e.printStackTrace();
350 }
351 }
352 glueLibLoaded[i] = res;
353 if(res) {
354 glueLibLoadedNumber++;
355 }
356 }
357
358 return dynLinkGlobal;
359 }
360
361 /**
362 * @param funcName
363 * @return
364 * @throws SecurityException if user is not granted access for the library set.
365 */
366 private final long dynamicLookupFunctionOnLibs(final String funcName) throws SecurityException {
367 if(!isToolLibLoaded() || null==funcName) {
368 if(DEBUG_LOOKUP && !isToolLibLoaded()) {
369 System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** Tool native library not loaded");
370 }
371 return 0;
372 }
373 long addr = 0;
374 NativeLibrary lib = null;
375
376 if( info.shallLookupGlobal() ) {
377 // Try a global symbol lookup first ..
378 // addr = NativeLibrary.dynamicLookupFunctionGlobal(funcName);
379 addr = dynLinkGlobal.lookupSymbolGlobal(funcName);
380 }
381 // Look up this function name in all known libraries
382 for (int i=0; 0==addr && i < toolLibraries.size(); i++) {
383 final NativeLibrary lib0 = toolLibraries.get(i);
384 if( null != lib0 && lib0.isOpen() ) {
385 lib = lib0;
386 addr = lib0.dynamicLookupFunction(funcName);
387 }
388 }
389 if(DEBUG_LOOKUP) {
390 final String libName = ( null == lib ) ? "GLOBAL" : lib.toString();
391 if(0!=addr) {
392 System.err.println("Lookup-Native: <" + funcName + "> 0x" + Long.toHexString(addr) + " in lib " + libName );
393 } else {
394 System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** in libs " + toolLibraries);
395 }
396 }
397 return addr;
398 }
399
400 private final long toolDynamicLookupFunction(final String funcName) {
401 if(0 != toolGetProcAddressHandle) {
402 final long addr = info.toolGetProcAddress(toolGetProcAddressHandle, funcName);
403 if(DEBUG_LOOKUP) {
404 if(0!=addr) {
405 System.err.println("Lookup-Tool: <"+funcName+"> 0x"+Long.toHexString(addr)+", via tool 0x"+Long.toHexString(toolGetProcAddressHandle));
406 }
407 }
408 return addr;
409 }
410 return 0;
411 }
412
413 @Override
414 public final void claimAllLinkPermission() throws SecurityException {
415 for(int i = 0; i<toolLibraries.size(); i++) {
416 final NativeLibrary lib = toolLibraries.get(i);
417 if( null != lib ) {
419 }
420 }
421 }
422 @Override
423 public final void releaseAllLinkPermission() throws SecurityException {
424 for(int i = 0; i<toolLibraries.size(); i++) {
425 final NativeLibrary lib = toolLibraries.get(i);
426 if( null != lib ) {
428 }
429 }
430 }
431
432 @Override
433 public final long dynamicLookupFunction(final String funcName) throws SecurityException {
434 if(!isToolLibLoaded() || null==funcName) {
435 if(DEBUG_LOOKUP && !isToolLibLoaded()) {
436 System.err.println("Lookup: <" + funcName + "> ** FAILED ** Tool native library not loaded");
437 }
438 return 0;
439 }
440
441 if(toolGetProcAddressFuncNameSet.contains(funcName)) {
442 return toolGetProcAddressHandle;
443 }
444
445 long addr = 0;
446 final boolean useToolGetProcAdressFirst = info.useToolGetProcAdressFirst(funcName);
447
448 if(useToolGetProcAdressFirst) {
449 addr = toolDynamicLookupFunction(funcName);
450 }
451 if(0==addr) {
452 addr = dynamicLookupFunctionOnLibs(funcName);
453 }
454 if(0==addr && !useToolGetProcAdressFirst) {
455 addr = toolDynamicLookupFunction(funcName);
456 }
457 return addr;
458 }
459
460 @Override
461 public final boolean isFunctionAvailable(final String funcName) throws SecurityException {
462 return 0 != dynamicLookupFunction(funcName);
463 }
464
465 /** Inherit access */
466 static final class GlueJNILibLoader extends JNILibLoaderBase {
467 protected static synchronized boolean loadLibrary(final String libname, final boolean ignoreError, final ClassLoader cl) {
468 return JNILibLoaderBase.loadLibrary(libname, ignoreError, cl);
469 }
470 }
471}
472
static synchronized boolean loadLibrary(final String libname, final boolean ignoreError, final ClassLoader cl)
Loads the library specified by libname, using the LoaderAction set by setLoadingAction(LoaderAction).
DynamicLibraryBundle(final DynamicLibraryBundleInfo info)
Instantiates and loads all NativeLibrarys incl.
final List< NativeLibrary > getToolLibraries()
Returns list of NativeLibrarys for each DynamicLibraryBundleInfo#getToolLibNames() in the same size a...
final NativeLibrary getToolLibrary(final int i)
Returns NativeLibrary at given index of all DynamicLibraryBundleInfo#getToolLibNames() in the same si...
final void destroy()
Unload all NativeLibrarys, and remove all references.
static final NativeLibrary loadFirstAvailable(final List< String > libNames, final boolean searchOSSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global, final String symbolName)
final boolean isOpen()
Returns true if library is loaded and open, otherwise false.
final DynamicLibraryBundleInfo getBundleInfo()
final boolean isFunctionAvailable(final String funcName)
Queries whether function 'funcName' is available.
static RunnableExecutor getDefaultRunnableExecutor()
Returns an AWT-EDT RunnableExecutor implementation if AWT is available, otherwise RunnableExecutor#cu...
final long dynamicLookupFunction(final String funcName)
Returns the function handle for function 'funcName'.
Provides low-level, relatively platform-independent access to shared ("native") libraries.
final void close()
Closes this native library.
static final NativeLibrary open(final String libName, final boolean searchOSSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global)
Opens the given native library, assuming it has the same base name on all platforms.
boolean useToolGetProcAdressFirst(String funcName)
long toolGetProcAddress(long toolGetProcAddressHandle, String funcName)
May implement the lookup function using the Tools facility.
List< List< String > > getToolLibNames()
If a SecurityManager is installed, user needs link permissions for the named libraries.
boolean searchToolLibInSystemPath()
Returns true if tool libraries shall be searched in the system path (default), otherwise false.
boolean shallLookupGlobal()
If method returns true and if a SecurityManager is installed, user needs link permissions for all lib...
List< String > getSymbolForToolLibPath()
Returns optional list of optional symbol names per getToolLibNames() in same order for an OS which re...
List< String > getGlueLibNames()
If a SecurityManager is installed, user needs link permissions for the named libraries.
RunnableExecutor getLibLoaderExecutor()
Returns a suitable RunnableExecutor implementation, which is being used to load the tool and glue nat...
List< String > getToolGetProcAddressFuncNameList()
May return the native libraries.
boolean searchToolLibSystemPathFirst()
Returns true if system path shall be searched first (default), rather than searching it last.
Low level secure dynamic linker access.
long lookupSymbolGlobal(String symbolName)
If a SecurityManager is installed, user needs link permissions for all libraries, i....
Interface callers may use ProcAddressHelper's reset helper method to install function pointers into a...
void invoke(boolean wait, Runnable r)
static final RunnableExecutor currentThreadExecutor
This RunnableExecutor implementation simply invokes Runnable#run() on the current thread.