|
| 1 | +/* |
| 2 | + * The contents of this file is dual-licensed under 2 |
| 3 | + * alternative Open Source/Free licenses: LGPL 2.1 or later and |
| 4 | + * Apache License 2.0. (starting with JNA version 4.0.0). |
| 5 | + * |
| 6 | + * You can freely decide which license you want to apply to |
| 7 | + * the project. |
| 8 | + * |
| 9 | + * You may obtain a copy of the LGPL License at: |
| 10 | + * |
| 11 | + * http://www.gnu.org/licenses/licenses.html |
| 12 | + * |
| 13 | + * A copy is also included in the downloadable source code package |
| 14 | + * containing JNA, in file "LGPL2.1". |
| 15 | + * |
| 16 | + * You may obtain a copy of the Apache License at: |
| 17 | + * |
| 18 | + * http://www.apache.org/licenses/ |
| 19 | + * |
| 20 | + * A copy is also included in the downloadable source code package |
| 21 | + * containing JNA, in file "AL2.0". |
| 22 | + */ |
| 23 | +package com.sun.jna; |
| 24 | + |
| 25 | +//import com.sun.jna.internal.ReflectionUtils; |
| 26 | +//import java.lang.reflect.InvocationHandler; |
| 27 | +//import java.lang.reflect.Method; |
| 28 | +//import java.lang.reflect.Proxy; |
| 29 | +//import java.util.HashMap; |
| 30 | +//import java.util.Map; |
| 31 | +//import java.util.WeakHashMap; |
| 32 | + |
| 33 | +/** Derive from this interface for all native library definitions. |
| 34 | + * |
| 35 | + * Define an instance of your library like this: |
| 36 | + * <pre><code> |
| 37 | + * MyNativeLibrary INSTANCE = (MyNativeLibrary) |
| 38 | + * Native.load("mylib", MyNativeLibrary.class); |
| 39 | + * </code></pre> |
| 40 | + * <p> |
| 41 | + * By convention, method names are identical to the native names, although you |
| 42 | + * can map java names to different native names by providing a |
| 43 | + * {@link FunctionMapper} as a value for key {@link #OPTION_FUNCTION_MAPPER} |
| 44 | + * in the options map passed to the |
| 45 | + * {@link Native#load(String, Class, Map)} call. |
| 46 | + * <p> |
| 47 | + * Although the names for structures and structure fields may be chosen |
| 48 | + * arbitrarily, they should correspond as closely as possible to the native |
| 49 | + * definitions. The same is true for parameter names. |
| 50 | + * <p> |
| 51 | + * This interface supports multiple, concurrent invocations of any library |
| 52 | + * methods on the Java side. Check your library documentation for its |
| 53 | + * multi-threading requirements on the native side. If a library is not safe |
| 54 | + * for simultaneous multi-threaded access, consider using |
| 55 | + * {@link Native#synchronizedLibrary} to prevent simultaneous multi-threaded |
| 56 | + * access to the native code. |
| 57 | + * <p> |
| 58 | + * <b>Optional fields</b><br> |
| 59 | + * Interface options will be automatically propagated to structures defined |
| 60 | + * within the library provided a call to |
| 61 | + * {@link Native#load(String,Class,Map)} is made prior to instantiating |
| 62 | + * any of those structures. One common way of ensuring this is to declare |
| 63 | + * an <b>INSTANCE</b> field in the interface which holds the |
| 64 | + * <code>load</code> result. |
| 65 | + * <p> |
| 66 | + * <b>OPTIONS</b> (an instance of {@link Map}), |
| 67 | + * <b>TYPE_MAPPER</b> (an instance of {@link TypeMapper}), |
| 68 | + * <b>STRUCTURE_ALIGNMENT</b> (one of the alignment types defined in |
| 69 | + * {@link Structure}), and <b>STRING_ENCODING</b> (a {@link String}) may also |
| 70 | + * be defined. If no instance of the interface has been instantiated, these |
| 71 | + * fields will be used to determine customization settings for structures and |
| 72 | + * methods defined within the interface. |
| 73 | + * <p> |
| 74 | + * |
| 75 | + * @author Todd Fast, [email protected] |
| 76 | + * @author Timothy Wall, [email protected] |
| 77 | + */ |
| 78 | +public interface Library { |
| 79 | +// /** Option key for a {@link TypeMapper} for the library. */ |
| 80 | +// String OPTION_TYPE_MAPPER = "type-mapper"; |
| 81 | +// /** Option key for a {@link FunctionMapper} for the library. */ |
| 82 | +// String OPTION_FUNCTION_MAPPER = "function-mapper"; |
| 83 | +// /** Option key for an {@link InvocationMapper} for the library. */ |
| 84 | +// String OPTION_INVOCATION_MAPPER = "invocation-mapper"; |
| 85 | +// /** Option key for structure alignment type ({@link Integer}), which should |
| 86 | +// * be one of the predefined alignment types in {@link Structure}. |
| 87 | +// */ |
| 88 | +// String OPTION_STRUCTURE_ALIGNMENT = "structure-alignment"; |
| 89 | +// /** <p>Option key for per-library String encoding. This affects conversions |
| 90 | +// * between Java unicode and native (<code>const char*</code>) strings (as |
| 91 | +// * arguments or Structure fields). |
| 92 | +// * </p> |
| 93 | +// * Defaults to {@link Native#getDefaultStringEncoding()}. |
| 94 | +// */ |
| 95 | +// String OPTION_STRING_ENCODING = "string-encoding"; |
| 96 | +// /** Option key for a boolean flag to allow any Java class instance as a |
| 97 | +// parameter. If no type mapper is found, the object is passed as a |
| 98 | +// pointer. |
| 99 | +// <em>NOTE:</em> This is for use with raw JNI interactions via the |
| 100 | +// JNIEnv data structure. |
| 101 | +// */ |
| 102 | +// String OPTION_ALLOW_OBJECTS = "allow-objects"; |
| 103 | +// /** Calling convention for the entire library. */ |
| 104 | +// String OPTION_CALLING_CONVENTION = "calling-convention"; |
| 105 | +// /** Flags to use when opening the native library (see {@link Native#open(String,int)}) */ |
| 106 | +// String OPTION_OPEN_FLAGS = "open-flags"; |
| 107 | +// /** <p>Class loader to use when searching for native libraries on the |
| 108 | +// * resource path (classpath). If not provided the current thread's |
| 109 | +// * context class loader is used.</p> |
| 110 | +// * If extracted from the resource path (i.e. bundled in a jar file), the |
| 111 | +// * loaded library's lifespan will mirror that of the class loader, which |
| 112 | +// * means you can use the same library in isolated contexts without |
| 113 | +// * conflict. |
| 114 | +// */ |
| 115 | +// String OPTION_CLASSLOADER = "classloader"; |
| 116 | +// |
| 117 | +// /** |
| 118 | +// * Supports a custom symbol provider for the NativeLibrary (see {@link SymbolProvider}) |
| 119 | +// */ |
| 120 | +// String OPTION_SYMBOL_PROVIDER = "symbol-provider"; |
| 121 | +// |
| 122 | +// static class Handler implements InvocationHandler { |
| 123 | +// |
| 124 | +// static final Method OBJECT_TOSTRING; |
| 125 | +// static final Method OBJECT_HASHCODE; |
| 126 | +// static final Method OBJECT_EQUALS; |
| 127 | +// |
| 128 | +// static { |
| 129 | +// try { |
| 130 | +// OBJECT_TOSTRING = Object.class.getMethod("toString"); |
| 131 | +// OBJECT_HASHCODE= Object.class.getMethod("hashCode"); |
| 132 | +// OBJECT_EQUALS = Object.class.getMethod("equals", Object.class); |
| 133 | +// } catch (Exception e) { |
| 134 | +// throw new Error("Error retrieving Object.toString() method"); |
| 135 | +// } |
| 136 | +// } |
| 137 | +// |
| 138 | +// /** |
| 139 | +// * FunctionInfo has to be immutable to to make the object visible |
| 140 | +// * to other threads fully initialized. This is a prerequisite for |
| 141 | +// * using the class in the double checked locking scenario of {@link Handler#invoke(Object, Method, Object[])} |
| 142 | +// */ |
| 143 | +// private static final class FunctionInfo { |
| 144 | +// final InvocationHandler handler; |
| 145 | +// final Function function; |
| 146 | +// final boolean isVarArgs; |
| 147 | +// final Object methodHandle; |
| 148 | +// final Map<String, ?> options; |
| 149 | +// final Class<?>[] parameterTypes; |
| 150 | +// |
| 151 | +// FunctionInfo(Object mh) { |
| 152 | +// this.handler = null; |
| 153 | +// this.function = null; |
| 154 | +// this.isVarArgs = false; |
| 155 | +// this.options = null; |
| 156 | +// this.parameterTypes = null; |
| 157 | +// this.methodHandle = mh; |
| 158 | +// } |
| 159 | +// |
| 160 | +// FunctionInfo(InvocationHandler handler, Function function, Class<?>[] parameterTypes, boolean isVarArgs, Map<String, ?> options) { |
| 161 | +// this.handler = handler; |
| 162 | +// this.function = function; |
| 163 | +// this.isVarArgs = isVarArgs; |
| 164 | +// this.options = options; |
| 165 | +// this.parameterTypes = parameterTypes; |
| 166 | +// this.methodHandle = null; |
| 167 | +// } |
| 168 | +// } |
| 169 | +// |
| 170 | +// private final NativeLibrary nativeLibrary; |
| 171 | +// private final Class<?> interfaceClass; |
| 172 | +// // Library invocation options |
| 173 | +// private final Map<String, Object> options; |
| 174 | +// private final InvocationMapper invocationMapper; |
| 175 | +// private final Map<Method, FunctionInfo> functions = new WeakHashMap<>(); |
| 176 | +// public Handler(String libname, Class<?> interfaceClass, Map<String, ?> options) { |
| 177 | +// |
| 178 | +// if (libname != null && "".equals(libname.trim())) { |
| 179 | +// throw new IllegalArgumentException("Invalid library name \"" + libname + "\""); |
| 180 | +// } |
| 181 | +// |
| 182 | +// if (!interfaceClass.isInterface()) { |
| 183 | +// throw new IllegalArgumentException(libname + " does not implement an interface: " + interfaceClass.getName()); |
| 184 | +// } |
| 185 | +// |
| 186 | +// this.interfaceClass = interfaceClass; |
| 187 | +// this.options = new HashMap<>(options); |
| 188 | +// int callingConvention = AltCallingConvention.class.isAssignableFrom(interfaceClass) |
| 189 | +// ? Function.ALT_CONVENTION |
| 190 | +// : Function.C_CONVENTION; |
| 191 | +// if (this.options.get(OPTION_CALLING_CONVENTION) == null) { |
| 192 | +// this.options.put(OPTION_CALLING_CONVENTION, Integer.valueOf(callingConvention)); |
| 193 | +// } |
| 194 | +// if (this.options.get(OPTION_CLASSLOADER) == null) { |
| 195 | +// this.options.put(OPTION_CLASSLOADER, interfaceClass.getClassLoader()); |
| 196 | +// } |
| 197 | +// this.nativeLibrary = NativeLibrary.getInstance(libname, this.options); |
| 198 | +// invocationMapper = (InvocationMapper)this.options.get(OPTION_INVOCATION_MAPPER); |
| 199 | +// } |
| 200 | +// |
| 201 | +// public NativeLibrary getNativeLibrary() { |
| 202 | +// return nativeLibrary; |
| 203 | +// } |
| 204 | +// |
| 205 | +// public String getLibraryName() { |
| 206 | +// return nativeLibrary.getName(); |
| 207 | +// } |
| 208 | +// |
| 209 | +// public Class<?> getInterfaceClass() { |
| 210 | +// return interfaceClass; |
| 211 | +// } |
| 212 | +// |
| 213 | +// @Override |
| 214 | +// public Object invoke(Object proxy, Method method, Object[] inArgs) |
| 215 | +// throws Throwable { |
| 216 | +// |
| 217 | +// // Intercept Object methods |
| 218 | +// if (OBJECT_TOSTRING.equals(method)) { |
| 219 | +// return "Proxy interface to " + nativeLibrary; |
| 220 | +// } else if (OBJECT_HASHCODE.equals(method)) { |
| 221 | +// return Integer.valueOf(hashCode()); |
| 222 | +// } else if (OBJECT_EQUALS.equals(method)) { |
| 223 | +// Object o = inArgs[0]; |
| 224 | +// if (o != null && Proxy.isProxyClass(o.getClass())) { |
| 225 | +// return Function.valueOf(Proxy.getInvocationHandler(o) == this); |
| 226 | +// } |
| 227 | +// return Boolean.FALSE; |
| 228 | +// } |
| 229 | +// |
| 230 | +// // Using the double-checked locking pattern to speed up function calls |
| 231 | +// FunctionInfo f = functions.get(method); |
| 232 | +// if(f == null) { |
| 233 | +// synchronized(functions) { |
| 234 | +// f = functions.get(method); |
| 235 | +// if (f == null) { |
| 236 | +// boolean isDefault = ReflectionUtils.isDefault(method); |
| 237 | +// if(! isDefault) { |
| 238 | +// boolean isVarArgs = Function.isVarArgs(method); |
| 239 | +// InvocationHandler handler = null; |
| 240 | +// if (invocationMapper != null) { |
| 241 | +// handler = invocationMapper.getInvocationHandler(nativeLibrary, method); |
| 242 | +// } |
| 243 | +// Function function = null; |
| 244 | +// Class<?>[] parameterTypes = null; |
| 245 | +// Map<String, Object> options = null; |
| 246 | +// if (handler == null) { |
| 247 | +// // Find the function to invoke |
| 248 | +// function = nativeLibrary.getFunction(method.getName(), method); |
| 249 | +// parameterTypes = method.getParameterTypes(); |
| 250 | +// options = new HashMap<>(this.options); |
| 251 | +// options.put(Function.OPTION_INVOKING_METHOD, method); |
| 252 | +// } |
| 253 | +// f = new FunctionInfo(handler, function, parameterTypes, isVarArgs, options); |
| 254 | +// } else { |
| 255 | +// f = new FunctionInfo(ReflectionUtils.getMethodHandle(method)); |
| 256 | +// } |
| 257 | +// functions.put(method, f); |
| 258 | +// } |
| 259 | +// } |
| 260 | +// } |
| 261 | +// if (f.methodHandle != null) { |
| 262 | +// return ReflectionUtils.invokeDefaultMethod(proxy, f.methodHandle, inArgs); |
| 263 | +// } else { |
| 264 | +// if (f.isVarArgs) { |
| 265 | +// inArgs = Function.concatenateVarArgs(inArgs); |
| 266 | +// } |
| 267 | +// if (f.handler != null) { |
| 268 | +// return f.handler.invoke(proxy, method, inArgs); |
| 269 | +// } |
| 270 | +// return f.function.invoke(method, f.parameterTypes, method.getReturnType(), inArgs, f.options); |
| 271 | +// } |
| 272 | +// } |
| 273 | +// } |
| 274 | +} |
0 commit comments