GlueGen: src/java/com/jogamp/gluegen/runtime/ProcAddressTable.java Source File

GlueGen v2.6.0-rc-20250712 GlueGen, Native Binding Generator for Java™ (public API).

ProcAddressTable.java
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (c) 2013 JogAmp Community. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * - Redistribution of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * - Redistribution in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of Sun Microsystems, Inc. or the names of
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * This software is provided "AS IS," without a warranty of any kind. ALL
21 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
22 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
23 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
24 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
25 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
26 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
27 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
28 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
29 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
30 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
31 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * You acknowledge that this software is not designed or intended for use
34 * in the design, construction, operation or maintenance of any nuclear
35 * facility.
36 */
37package com.jogamp.gluegen.runtime;
38
39import com.jogamp.common.os.DynamicLookupHelper;
40import com.jogamp.common.util.SecurityUtil;
41
42import java.io.BufferedOutputStream;
43import java.io.File;
44import java.io.FileOutputStream;
45import java.io.IOException;
46import java.io.PrintStream;
47import java.lang.reflect.AccessibleObject;
48import java.lang.reflect.Field;
49import java.security.PrivilegedAction;
50import java.util.Iterator;
51import java.util.LinkedHashSet;
52import java.util.Map;
53import java.util.Set;
54import java.util.SortedMap;
55import java.util.TreeMap;
56
57/**
58 * Superclass for all generated ProcAddressTables.
59 *
60 * A ProcAddressTable is a cache of pointers to the dynamically-linkable C
61 * functions this autogenerated Java binding has exposed. Some
62 * libraries such as OpenGL, OpenAL and others define function pointer
63 * signatures rather than statically linkable entry points for the
64 * purposes of being able to query at run-time whether a particular
65 * extension is available. This table acts as a cache of these
66 * function pointers. Each function pointer is typically looked up at
67 * run-time by a platform-dependent mechanism such as dlsym(),
68 * wgl/glXGetProcAddress(), or alGetProcAddress(). If the field containing the function
69 * pointer is 0, the function is considered to be unavailable and can
70 * not be called.
71 *
72 * @author Kenneth Russel
73 * @author Michael Bien
74 * @author Sven Gothel
75 *
76 * @see FunctionAddressResolver
77 * @see DynamicLookupHelper
78 */
79 public abstract class ProcAddressTable {
80
81 private static final String PROCADDRESS_VAR_PREFIX = "_addressof_";
82 private static final int PROCADDRESS_VAR_PREFIX_LEN = PROCADDRESS_VAR_PREFIX.length();
83
84 protected static boolean DEBUG;
85 protected static String DEBUG_PREFIX;
86 protected static int debugNum;
87
88 private final FunctionAddressResolver resolver;
89
90 static {
91 SecurityUtil.doPrivileged(new PrivilegedAction<Object>() {
92 @Override
93 public Object run() {
94 DEBUG = (System.getProperty("jogamp.debug.ProcAddressHelper") != null);
95 if (DEBUG) {
96 DEBUG_PREFIX = System.getProperty("jogamp.debug.ProcAddressHelper.prefix");
97 }
98 return null;
99 }
100 });
101 }
102
103 public ProcAddressTable() {
104 this(new One2OneResolver());
105 }
106
107 public ProcAddressTable(final FunctionAddressResolver resolver) {
108 this.resolver = resolver;
109 }
110
111
112 /**
113 * Resets the complete table.
114 * <p>
115 * If a {@link SecurityManager} is installed, user needs link permissions
116 * for <b>all</b> libraries, i.e. for <code>new RuntimePermission("loadLibrary.*");</code>!
117 * </p>
118 * @throws SecurityException if user is not granted access for all libraries.
119 */
120 public void reset(final DynamicLookupHelper lookup) throws SecurityException, RuntimeException {
121 if(null==lookup) {
122 throw new RuntimeException("Passed null DynamicLookupHelper");
123 }
124
125 final Field[] fields = getClass().getDeclaredFields();
126
127 final PrintStream dout;
128 if (DEBUG) {
129 dout = getDebugOutStream();
130 dout.println(getClass().getName()+".reset() (w/ "+fields.length+" prospective fields)");
131 } else {
132 dout = null;
133 }
134
135 // All at once - performance.
136 AccessibleObject.setAccessible(fields, true);
137 lookup.claimAllLinkPermission();
138 try {
139 for (int i = 0; i < fields.length; ++i) {
140 final String fieldName = fields[i].getName();
141 if ( isAddressField(fieldName) ) {
142 final String funcName = fieldToFunctionName(fieldName);
143 setEntry(fields[i], funcName, lookup);
144 }
145 }
146 } finally {
147 lookup.releaseAllLinkPermission();
148 }
149
150 if (DEBUG) {
151 dout.flush();
152 if (DEBUG_PREFIX != null) {
153 dout.close();
154 }
155 }
156 }
157
158 /**
159 * Initializes the mapping for a single function.
160 * <p>
161 * If a {@link SecurityManager} is installed, user needs link permissions
162 * for <b>all</b> libraries, i.e. for <code>new RuntimePermission("loadLibrary.*");</code>!
163 * </p>
164 *
165 * @throws IllegalArgumentException if this function is not in this table.
166 * @throws SecurityException if user is not granted access for all libraries.
167 */
168 public void initEntry(final String name, final DynamicLookupHelper lookup) throws SecurityException, IllegalArgumentException {
169 final Field addressField = fieldForFunction(name);
170 addressField.setAccessible(true);
171 setEntry(addressField, name, lookup);
172 }
173
174 private final void setEntry(final Field addressField, final String funcName, final DynamicLookupHelper lookup) throws SecurityException {
175 try {
176 assert (addressField.getType() == Long.TYPE);
177 final long newProcAddress = resolver.resolve(funcName, lookup); // issues SecurityUtil.checkLinkPermission(String)
178 addressField.setLong(this, newProcAddress);
179 if (DEBUG) {
180 getDebugOutStream().println(" " + addressField.getName() + " -> 0x" + Long.toHexString(newProcAddress));
181 }
182 } catch (final Exception e) {
183 throw new RuntimeException("Can not get proc address for method \""
184 + funcName + "\": Couldn't set value of field \"" + addressField, e);
185 }
186 }
187
188 private final String fieldToFunctionName(final String addressFieldName) {
189 return addressFieldName.substring(PROCADDRESS_VAR_PREFIX_LEN);
190 }
191
192 private final Field fieldForFunction(final String name) throws IllegalArgumentException {
193 try {
194 return getClass().getDeclaredField(PROCADDRESS_VAR_PREFIX + name);
195 } catch (final NoSuchFieldException ex) {
196 throw new IllegalArgumentException(getClass().getName() +" has no entry for the function '"+name+"'.", ex);
197 }
198 }
199
200 /**
201 * Warning: Returns an accessible probably protected field!
202 * <p>
203 * Caller should have checked link permissions
204 * for <b>all</b> libraries, i.e. for <code>new RuntimePermission("loadLibrary.*");</code>
205 * <i>if</i> exposing the field or address!
206 * </p>
207 */
208 private final Field fieldForFunctionInSec(final String name) throws IllegalArgumentException {
209 return SecurityUtil.doPrivileged(new PrivilegedAction<Field>() {
210 @Override
211 public Field run() {
212 try {
213 final Field addressField = ProcAddressTable.this.getClass().getDeclaredField(PROCADDRESS_VAR_PREFIX + name);
214 addressField.setAccessible(true); // we need to read the protected value!
215 return addressField;
216 } catch (final NoSuchFieldException ex) {
217 throw new IllegalArgumentException(getClass().getName() +" has no entry for the function '"+name+"'.", ex);
218 }
219 }
220 } );
221 }
222
223 private final boolean isAddressField(final String fieldName) {
224 return fieldName.startsWith(PROCADDRESS_VAR_PREFIX);
225 }
226
227 private final static PrintStream getDebugOutStream() {
228 PrintStream out = null;
229 if (DEBUG) {
230 if (DEBUG_PREFIX != null) {
231 try {
232 out = new PrintStream(new BufferedOutputStream(new FileOutputStream(DEBUG_PREFIX + File.separatorChar
233 + "procaddresstable-" + (++debugNum) + ".txt")));
234 } catch (final IOException e) {
235 e.printStackTrace();
236 out = System.err;
237 }
238 } else {
239 out = System.err;
240 }
241 }
242 return out;
243 }
244
245 /**
246 * Returns this table as map with the function name as key and the address as value.
247 */
248 private final Map<String, Long> toMap() {
249 final SortedMap<String, Long> map = new TreeMap<String, Long>();
250
251 final Field[] fields = getClass().getFields();
252 try {
253 for (int i = 0; i < fields.length; ++i) {
254 final String addressFieldName = fields[i].getName();
255 if (isAddressField(addressFieldName)) {
256 map.put(fieldToFunctionName(addressFieldName), (Long)fields[i].get(this));
257 }
258 }
259 } catch (final IllegalArgumentException ex) {
260 throw new RuntimeException(ex);
261 } catch (final IllegalAccessException ex) {
262 throw new RuntimeException(ex);
263 }
264
265 return map;
266 }
267
268 /**
269 * Returns true only if non null function pointer to this function exists.
270 */
271 public final boolean isFunctionAvailable(final String functionName) {
272 try{
273 return isFunctionAvailableImpl(functionName);
274 } catch (final IllegalArgumentException ex) {
275 return false;
276 }
277 }
278
279 /**
280 * This is a convenience method to query the native function existence by name.
281 * <p>
282 * It lets you avoid having to
283 * manually compute the &quot;{@link #PROCADDRESS_VAR_PREFIX} + &lt;functionName&gt;&quot;
284 * member variable name and look it up via reflection.
285 * </p>
286 *
287 * @throws IllegalArgumentException if this function is not in this table.
288 */
289 protected boolean isFunctionAvailableImpl(final String functionName) throws IllegalArgumentException {
290 final Field addressField = fieldForFunctionInSec(functionName);
291 try {
292 return 0 != addressField.getLong(this);
293 } catch (final IllegalAccessException ex) {
294 throw new RuntimeException(ex);
295 }
296 }
297
298 /**
299 * This is a convenience method to query the native function handle by name.
300 * <p>
301 * It lets you avoid having to
302 * manually compute the &quot;{@link #PROCADDRESS_VAR_PREFIX} + &lt;functionName&gt;&quot;
303 * member variable name and look it up via reflection.
304 * </p>
305 * <p>
306 * If a {@link SecurityManager} is installed, user needs link permissions
307 * for <b>all</b> libraries, i.e. for <code>new RuntimePermission("loadLibrary.*");</code>!
308 * </p>
309 *
310 * @throws IllegalArgumentException if this function is not in this table.
311 * @throws SecurityException if user is not granted access for all libraries.
312 */
313 public long getAddressFor(final String functionName) throws SecurityException, IllegalArgumentException {
314 SecurityUtil.checkAllLinkPermission();
315 final Field addressField = fieldForFunctionInSec(functionName);
316 try {
317 return addressField.getLong(this);
318 } catch (final IllegalAccessException ex) {
319 throw new RuntimeException(ex);
320 }
321 }
322
323 /**
324 * Returns all functions pointing to null.
325 */
326 public final Set<String> getNullPointerFunctions() {
327 final Map<String, Long> table = toMap();
328 final Set<String> nullPointers = new LinkedHashSet<String>();
329 for (final Iterator<Map.Entry<String, Long>> it = table.entrySet().iterator(); it.hasNext();) {
330 final Map.Entry<String, Long> entry = it.next();
331 final long address = entry.getValue().longValue();
332 if(address == 0) {
333 nullPointers.add(entry.getKey());
334 }
335 }
336 return nullPointers;
337 }
338
339 @Override
340 public final String toString() {
341 return getClass().getName()+""+toMap();
342 }
343
344 private static class One2OneResolver implements FunctionAddressResolver {
345 @Override
346 public long resolve(final String name, final DynamicLookupHelper lookup) throws SecurityException {
347 return lookup.dynamicLookupFunction(name);
348 }
349 }
350
351
352}
com.jogamp.common.util.SecurityUtil
Definition: SecurityUtil.java:39
com.jogamp.common.util.SecurityUtil.doPrivileged
static< T > T doPrivileged(final PrivilegedAction< T > o)
Call wrapper for java.security.AccessController#doPrivileged(PrivilegedAction).
Definition: SecurityUtil.java:78
com.jogamp.common.util.SecurityUtil.checkAllLinkPermission
static final void checkAllLinkPermission()
Throws an SecurityException if an installed SecurityManager does not permit to dynamically link to al...
Definition: SecurityUtil.java:193
com.jogamp.gluegen.runtime.ProcAddressTable
Superclass for all generated ProcAddressTables.
Definition: ProcAddressTable.java:79
com.jogamp.gluegen.runtime.ProcAddressTable.reset
void reset(final DynamicLookupHelper lookup)
Resets the complete table.
Definition: ProcAddressTable.java:120
com.jogamp.gluegen.runtime.ProcAddressTable.getAddressFor
long getAddressFor(final String functionName)
This is a convenience method to query the native function handle by name.
Definition: ProcAddressTable.java:313
com.jogamp.gluegen.runtime.ProcAddressTable.isFunctionAvailableImpl
boolean isFunctionAvailableImpl(final String functionName)
This is a convenience method to query the native function existence by name.
Definition: ProcAddressTable.java:289
com.jogamp.gluegen.runtime.ProcAddressTable.initEntry
void initEntry(final String name, final DynamicLookupHelper lookup)
Initializes the mapping for a single function.
Definition: ProcAddressTable.java:168
com.jogamp.gluegen.runtime.ProcAddressTable.DEBUG_PREFIX
static String DEBUG_PREFIX
Definition: ProcAddressTable.java:85
com.jogamp.gluegen.runtime.ProcAddressTable.DEBUG
static boolean DEBUG
Definition: ProcAddressTable.java:84
com.jogamp.gluegen.runtime.ProcAddressTable.debugNum
static int debugNum
Definition: ProcAddressTable.java:86
com.jogamp.gluegen.runtime.ProcAddressTable.toString
final String toString()
Definition: ProcAddressTable.java:340
com.jogamp.gluegen.runtime.ProcAddressTable.isFunctionAvailable
final boolean isFunctionAvailable(final String functionName)
Returns true only if non null function pointer to this function exists.
Definition: ProcAddressTable.java:271
com.jogamp.gluegen.runtime.ProcAddressTable.ProcAddressTable
ProcAddressTable(final FunctionAddressResolver resolver)
Definition: ProcAddressTable.java:107
com.jogamp.gluegen.runtime.ProcAddressTable.ProcAddressTable
ProcAddressTable()
Definition: ProcAddressTable.java:103
com.jogamp.gluegen.runtime.ProcAddressTable.getNullPointerFunctions
final Set< String > getNullPointerFunctions()
Returns all functions pointing to null.
Definition: ProcAddressTable.java:326
com.jogamp.common.os.DynamicLookupHelper
Interface callers may use ProcAddressHelper's reset helper method to install function pointers into a...
Definition: DynamicLookupHelper.java:49
com.jogamp.gluegen.runtime.FunctionAddressResolver
Definition: FunctionAddressResolver.java:40
com.jogamp.gluegen.runtime.FunctionAddressResolver.resolve
long resolve(String name, DynamicLookupHelper lookup)
Resolves the name of the function bound to the method and returns the address.