jaulib v1.3.0
Jau Support Library (C++, Java, ..)
DynamicLibraryBundle.java
Go to the documentation of this file.
1/**
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2010 Gothel Software e.K.
5 * Copyright (c) 2010 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 */
26
27package org.jau.sys.dl;
28
29import java.util.ArrayList;
30import java.util.Arrays;
31import java.util.HashSet;
32import java.util.List;
33
34import org.jau.sys.JNILibrary;
35import org.jau.util.parallel.RunnableExecutor;
36
37/**
38 * Provides bundling of:<br>
39 * <ul>
40 * <li>The to-be-glued native library, eg OpenGL32.dll. From here on this is referred as the Tool.</li>
41 * <li>The JNI glue-code native library, eg jogl_desktop.dll. From here on this is referred as the Glue</li>
42 * </ul>
43 * <p>
44 * An {@link DynamicLibraryBundleInfo} instance is being passed in the constructor,
45 * providing the required information about the tool and glue libraries.
46 * The ClassLoader of it's implementation is also being used to help locating the native libraries.
47 * </p>
48 * An instance provides a complete {@link com.jogamp.common.os.DynamicLookupHelper}
49 * to {@link com.jogamp.gluegen.runtime.ProcAddressTable#reset(com.jogamp.common.os.DynamicLookupHelper) reset}
50 * the {@link com.jogamp.gluegen.runtime.ProcAddressTable}.<br>
51 * At construction, it:
52 * <ul>
53 * <li> loads the Tool native library via
54 * {@link com.jogamp.common.os.NativeLibrary#open(java.lang.String, java.lang.ClassLoader, boolean) NativeLibrary's open method}</li>
55 * <li> loads the {@link org.jau.sys.JNIJarLibrary.common.jvm.JNILibLoaderBase#loadLibrary(java.lang.String, java.lang.String[], boolean, ClassLoader) Glue native library}</li>
56 * <li> resolves the Tool's {@link com.jogamp.common.os.DynamicLibraryBundleInfo#getToolGetProcAddressFuncNameList() GetProcAddress}. (optional)</li>
57 * </ul>
58 */
60 private final DynamicLibraryBundleInfo info;
61
62 protected final List<NativeLibrary> nativeLibraries;
63 private final DynamicLinker dynLinkGlobal;
64 private final List<List<String>> toolLibNames;
65 private final List<String> glueLibNames;
66 private final boolean[] toolLibLoaded;
67
68 private int toolLibLoadedNumber;
69
70 private final boolean[] glueLibLoaded;
71 private int glueLibLoadedNumber;
72
73 private long toolGetProcAddressHandle;
74 private boolean toolGetProcAddressComplete;
75 private HashSet<String> toolGetProcAddressFuncNameSet;
76 private final List<String> toolGetProcAddressFuncNameList;
77
78 /** Returns the default {@link RunnableExecutor#currentThreadExecutor}. */
81 }
82
83 /**
84 * Instantiates and loads all {@link NativeLibrary}s incl. JNI libraries.
85 * <p>
86 * The ClassLoader of the {@link DynamicLibraryBundleInfo} implementation class
87 * is being used to help locating the native libraries.
88 * </p>
89 */
91 if(null==info) {
92 throw new RuntimeException("Null DynamicLibraryBundleInfo");
93 }
94 this.info = info;
95 if(DEBUG) {
96 System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.init start with: "+info.getClass().getName());
97 }
98 nativeLibraries = new ArrayList<NativeLibrary>();
99 toolLibNames = info.getToolLibNames();
100 glueLibNames = info.getGlueLibNames();
101 toolLibLoaded = new boolean[toolLibNames.size()];
102 if(DEBUG) {
103 if( toolLibNames.size() == 0 ) {
104 System.err.println("No Tool native library names given");
105 }
106
107 if( glueLibNames.size() == 0 ) {
108 System.err.println("No Glue native library names given");
109 }
110 }
111
112 for(int i=toolLibNames.size()-1; i>=0; i--) {
113 toolLibLoaded[i] = false;
114 }
115 glueLibLoaded = new boolean[glueLibNames.size()];
116 for(int i=glueLibNames.size()-1; i>=0; i--) {
117 glueLibLoaded[i] = false;
118 }
119
120 {
121 final DynamicLinker[] _dynLinkGlobal = { null };
122 info.getLibLoaderExecutor().invoke(true, new Runnable() {
123 @Override
124 public void run() {
125 _dynLinkGlobal[0] = loadLibraries();
126 } } ) ;
127 dynLinkGlobal = _dynLinkGlobal[0];
128 }
129
130 toolGetProcAddressFuncNameList = info.getToolGetProcAddressFuncNameList();
131 if( null != toolGetProcAddressFuncNameList ) {
132 toolGetProcAddressFuncNameSet = new HashSet<String>(toolGetProcAddressFuncNameList);
133 toolGetProcAddressHandle = getToolGetProcAddressHandle();
134 toolGetProcAddressComplete = 0 != toolGetProcAddressHandle;
135 } else {
136 toolGetProcAddressFuncNameSet = new HashSet<String>();
137 toolGetProcAddressHandle = 0;
138 toolGetProcAddressComplete = true;
139 }
140 if(DEBUG) {
141 System.err.println("DynamicLibraryBundle.init Summary: "+info.getClass().getName());
142 System.err.println(" toolGetProcAddressFuncNameList: "+toolGetProcAddressFuncNameList+", complete: "+toolGetProcAddressComplete+", 0x"+Long.toHexString(toolGetProcAddressHandle));
143 System.err.println(" Tool Lib Names : "+toolLibNames);
144 System.err.println(" Tool Lib Loaded: "+getToolLibLoadedNumber()+"/"+getToolLibNumber()+" "+Arrays.toString(toolLibLoaded)+", complete "+isToolLibComplete());
145 System.err.println(" Glue Lib Names : "+glueLibNames);
146 System.err.println(" Glue Lib Loaded: "+getGlueLibLoadedNumber()+"/"+getGlueLibNumber()+" "+Arrays.toString(glueLibLoaded)+", complete "+isGlueLibComplete());
147 System.err.println(" All Complete: "+isLibComplete());
148 System.err.println(" LibLoaderExecutor: "+info.getLibLoaderExecutor().getClass().getName());
149 }
150 }
151
152 /** Unload all {@link NativeLibrary}s, and remove all references. */
153 public final void destroy() {
154 if(DEBUG) {
155 System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.destroy() START: "+info.getClass().getName());
156 }
157 toolGetProcAddressFuncNameSet = null;
158 toolGetProcAddressHandle = 0;
159 toolGetProcAddressComplete = false;
160 for(int i = 0; i<nativeLibraries.size(); i++) {
161 nativeLibraries.get(i).close();
162 }
163 nativeLibraries.clear();
164 toolLibNames.clear();
165 glueLibNames.clear();
166 if(DEBUG) {
167 System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.destroy() END: "+info.getClass().getName());
168 }
169 }
170
171 public final boolean isLibComplete() {
173 }
174
175 public final int getToolLibNumber() {
176 return toolLibNames.size();
177 }
178
179 public final int getToolLibLoadedNumber() {
180 return toolLibLoadedNumber;
181 }
182
183 /**
184 * @return true if all tool libraries are loaded,
185 * otherwise false.
186 *
187 * @see DynamicLibraryBundleInfo#getToolLibNames()
188 */
189 public final boolean isToolLibComplete() {
190 final int toolLibNumber = getToolLibNumber();
191 return toolGetProcAddressComplete &&
192 ( 0 == toolLibNumber || null != dynLinkGlobal ) &&
193 toolLibNumber == getToolLibLoadedNumber();
194 }
195
196 public final boolean isToolLibLoaded() {
197 return 0 < toolLibLoadedNumber;
198 }
199
200 public final boolean isToolLibLoaded(final int i) {
201 if(0 <= i && i < toolLibLoaded.length) {
202 return toolLibLoaded[i];
203 }
204 return false;
205 }
206
207 public final int getGlueLibNumber() {
208 return glueLibNames.size();
209 }
210
211 public final int getGlueLibLoadedNumber() {
212 return glueLibLoadedNumber;
213 }
214
215 /**
216 * @return true if the last entry has been loaded,
217 * while ignoring the preload dependencies.
218 * Otherwise false.
219 *
220 * @see DynamicLibraryBundleInfo#getGlueLibNames()
221 */
222 public final boolean isGlueLibComplete() {
223 return 0 == getGlueLibNumber() || isGlueLibLoaded(getGlueLibNumber() - 1);
224 }
225
226 public final boolean isGlueLibLoaded(final int i) {
227 if(0 <= i && i < glueLibLoaded.length) {
228 return glueLibLoaded[i];
229 }
230 return false;
231 }
232
233 public final DynamicLibraryBundleInfo getBundleInfo() { return info; }
234
235 protected final long getToolGetProcAddressHandle() throws SecurityException {
236 if(!isToolLibLoaded()) {
237 return 0;
238 }
239 long aptr = 0;
240 for (int i=0; i < toolGetProcAddressFuncNameList.size(); i++) {
241 final String name = toolGetProcAddressFuncNameList.get(i);
242 aptr = dynamicLookupFunctionOnLibs(name);
243 if(DEBUG) {
244 System.err.println("getToolGetProcAddressHandle: "+name+" -> 0x"+Long.toHexString(aptr));
245 }
246 }
247 return aptr;
248 }
249
250 protected static final NativeLibrary loadFirstAvailable(final List<String> libNames,
251 final boolean searchSystemPath,
252 final boolean searchSystemPathFirst,
253 final ClassLoader loader, final boolean global) throws SecurityException {
254 for (int i=0; i < libNames.size(); i++) {
255 final NativeLibrary lib = NativeLibrary.open(libNames.get(i), searchSystemPath, searchSystemPathFirst, loader, global);
256 if (lib != null) {
257 return lib;
258 }
259 }
260 return null;
261 }
262
263 final DynamicLinker loadLibraries() throws SecurityException {
264 int i;
265 toolLibLoadedNumber = 0;
266 final ClassLoader cl = info.getClass().getClassLoader();
267 NativeLibrary lib = null;
268 DynamicLinker dynLinkGlobal = null;
269
270 for (i=0; i < toolLibNames.size(); i++) {
271 final List<String> libNames = toolLibNames.get(i);
272 if( null != libNames && libNames.size() > 0 ) {
273 lib = loadFirstAvailable(libNames,
276 cl, info.shallLinkGlobal());
277 if ( null == lib ) {
278 if(DEBUG) {
279 System.err.println("Unable to load any Tool library of: "+libNames);
280 }
281 } else {
282 if( null == dynLinkGlobal ) {
283 dynLinkGlobal = lib.dynamicLinker();
284 }
285 nativeLibraries.add(lib);
286 toolLibLoaded[i]=true;
287 toolLibLoadedNumber++;
288 if(DEBUG) {
289 System.err.println("Loaded Tool library: "+lib);
290 }
291 }
292 }
293 }
294 if( toolLibNames.size() > 0 && !isToolLibLoaded() ) {
295 if(DEBUG) {
296 System.err.println("No Tool libraries loaded");
297 }
298 return dynLinkGlobal;
299 }
300
301 glueLibLoadedNumber = 0;
302 for (i=0; i < glueLibNames.size(); i++) {
303 final String libName = glueLibNames.get(i);
304 final boolean ignoreError = true;
305 boolean res;
306 try {
307 res = JNILibrary.loadLibrary(libName, ignoreError, cl);
308 if(DEBUG && !res) {
309 System.err.println("Info: Could not load JNI/Glue library: "+libName);
310 }
311 } catch (final UnsatisfiedLinkError e) {
312 res = false;
313 if(DEBUG) {
314 System.err.println("Unable to load JNI/Glue library: "+libName);
315 e.printStackTrace();
316 }
317 }
318 glueLibLoaded[i] = res;
319 if(res) {
320 glueLibLoadedNumber++;
321 }
322 }
323
324 return dynLinkGlobal;
325 }
326
327 /**
328 * @param funcName
329 * @return
330 * @throws SecurityException if user is not granted access for the library set.
331 */
332 private final long dynamicLookupFunctionOnLibs(final String funcName) throws SecurityException {
333 if(!isToolLibLoaded() || null==funcName) {
334 if(DEBUG_LOOKUP && !isToolLibLoaded()) {
335 System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** Tool native library not loaded");
336 }
337 return 0;
338 }
339 long addr = 0;
340 NativeLibrary lib = null;
341
342 if( info.shallLookupGlobal() ) {
343 // Try a global symbol lookup first ..
344 // addr = NativeLibrary.dynamicLookupFunctionGlobal(funcName);
345 addr = dynLinkGlobal.lookupSymbolGlobal(funcName);
346 }
347 // Look up this function name in all known libraries
348 for (int i=0; 0==addr && i < nativeLibraries.size(); i++) {
349 lib = nativeLibraries.get(i);
350 addr = lib.dynamicLookupFunction(funcName);
351 }
352 if(DEBUG_LOOKUP) {
353 final String libName = ( null == lib ) ? "GLOBAL" : lib.toString();
354 if(0!=addr) {
355 System.err.println("Lookup-Native: <" + funcName + "> 0x" + Long.toHexString(addr) + " in lib " + libName );
356 } else {
357 System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** in libs " + nativeLibraries);
358 }
359 }
360 return addr;
361 }
362
363 private final long toolDynamicLookupFunction(final String funcName) {
364 if(0 != toolGetProcAddressHandle) {
365 final long addr = info.toolGetProcAddress(toolGetProcAddressHandle, funcName);
366 if(DEBUG_LOOKUP) {
367 if(0!=addr) {
368 System.err.println("Lookup-Tool: <"+funcName+"> 0x"+Long.toHexString(addr)+", via tool 0x"+Long.toHexString(toolGetProcAddressHandle));
369 }
370 }
371 return addr;
372 }
373 return 0;
374 }
375
376 @Override
377 public final void claimAllLinkPermission() throws SecurityException {
378 for (int i=0; i < nativeLibraries.size(); i++) {
379 nativeLibraries.get(i).claimAllLinkPermission();
380 }
381 }
382 @Override
383 public final void releaseAllLinkPermission() throws SecurityException {
384 for (int i=0; i < nativeLibraries.size(); i++) {
385 nativeLibraries.get(i).releaseAllLinkPermission();
386 }
387 }
388
389 @Override
390 public final long dynamicLookupFunction(final String funcName) throws SecurityException {
391 if(!isToolLibLoaded() || null==funcName) {
392 if(DEBUG_LOOKUP && !isToolLibLoaded()) {
393 System.err.println("Lookup: <" + funcName + "> ** FAILED ** Tool native library not loaded");
394 }
395 return 0;
396 }
397
398 if(toolGetProcAddressFuncNameSet.contains(funcName)) {
399 return toolGetProcAddressHandle;
400 }
401
402 long addr = 0;
403 final boolean useToolGetProcAdressFirst = info.useToolGetProcAdressFirst(funcName);
404
405 if(useToolGetProcAdressFirst) {
406 addr = toolDynamicLookupFunction(funcName);
407 }
408 if(0==addr) {
409 addr = dynamicLookupFunctionOnLibs(funcName);
410 }
411 if(0==addr && !useToolGetProcAdressFirst) {
412 addr = toolDynamicLookupFunction(funcName);
413 }
414 return addr;
415 }
416
417 @Override
418 public final boolean isFunctionAvailable(final String funcName) throws SecurityException {
419 return 0 != dynamicLookupFunction(funcName);
420 }
421}
422
final DynamicLibraryBundleInfo getBundleInfo()
final boolean isToolLibLoaded(final int i)
static final NativeLibrary loadFirstAvailable(final List< String > libNames, final boolean searchSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global)
DynamicLibraryBundle(final DynamicLibraryBundleInfo info)
Instantiates and loads all NativeLibrarys incl.
final long dynamicLookupFunction(final String funcName)
Returns the function handle for function 'funcName'.
final boolean isGlueLibLoaded(final int i)
final List< NativeLibrary > nativeLibraries
final void destroy()
Unload all NativeLibrarys, and remove all references.
static RunnableExecutor getDefaultRunnableExecutor()
Returns the default RunnableExecutor#currentThreadExecutor.
final boolean isFunctionAvailable(final String funcName)
Queries whether function 'funcName' is available.
Provides low-level, relatively platform-independent access to shared ("native") libraries.
static final NativeLibrary open(final String libName, final boolean searchSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global)
Opens the given native library, assuming it has the same base name on all platforms.
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.
boolean useToolGetProcAdressFirst(String funcName)
RunnableExecutor getLibLoaderExecutor()
Returns a suitable RunnableExecutor implementation, which is being used to load the tool and glue nat...
List< String > getGlueLibNames()
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.
List< List< String > > getToolLibNames()
If a SecurityManager is installed, user needs link permissions for the named libraries.
boolean shallLookupGlobal()
If method returns true and if a SecurityManager is installed, user needs link permissions for all lib...
long toolGetProcAddress(long toolGetProcAddressHandle, String funcName)
May implement the lookup function using the Tools facility.
Low level secure dynamic linker access.
long lookupSymbolGlobal(String symbolName)
If a SecurityManager is installed, user needs link permissions for all libraries, i....
void invoke(boolean wait, Runnable r)
static final RunnableExecutor currentThreadExecutor
This RunnableExecutor implementation simply invokes Runnable#run() on the current thread.