1 | /* |
2 | * NativeCall.java |
3 | * |
4 | * Created on 07.09.2004. |
5 | * |
6 | * eaio: NativeCall - calling operating system methods from Java |
7 | * Copyright (c) 2004-2006 Johann Burkard (<mailto:jb@eaio.com>) |
8 | * <http://eaio.com> |
9 | * |
10 | * Permission is hereby granted, free of charge, to any person obtaining a |
11 | * copy of this software and associated documentation files (the "Software"), |
12 | * to deal in the Software without restriction, including without limitation |
13 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
14 | * and/or sell copies of the Software, and to permit persons to whom the |
15 | * Software is furnished to do so, subject to the following conditions: |
16 | * |
17 | * The above copyright notice and this permission notice shall be included |
18 | * in all copies or substantial portions of the Software. |
19 | * |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
21 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
23 | * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
24 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
25 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
26 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
27 | * |
28 | */ |
29 | package com.eaio.nativecall; |
30 | |
31 | import java.io.IOException; |
32 | |
33 | import sun.misc.ServiceConfigurationError; |
34 | |
35 | import com.eaio.util.lang.NativeLoader; |
36 | |
37 | /** |
38 | * NativeCall loads the native library and prepares the matching |
39 | * {@link com.eaio.nativecall.Verifier}. |
40 | * <p> |
41 | * Before being able to use NativeCall, the {@link #init()} method must have |
42 | * been called: |
43 | * <pre> |
44 | * try { |
45 | * NativeCall.init(); |
46 | * } |
47 | * catch (IOException ex) { ... } |
48 | * catch (SecurityException ex) { ... } |
49 | * catch (UnsatisfiedLinkError er) { ... } |
50 | * catch (sun.misc.ServiceConfigurationError) { ... } |
51 | * catch (UnsupportedOperationException) { ... } |
52 | * </pre> |
53 | * After usage, each NativeCall object must be destroyed to release |
54 | * resources. This is done by calling the {@link #destroy()} method. Failure |
55 | * to call this method might result in memory leaks. |
56 | * |
57 | * @see #destroy() |
58 | * @see #init() |
59 | * @author <a href="mailto:jb@eaio.com">Johann Burkard</a> |
60 | * @version $Id: NativeCall.java,v 1.3 2006/04/19 20:54:58 grnull Exp $ |
61 | */ |
62 | public abstract class NativeCall { |
63 | |
64 | /** |
65 | * The error code of the last call. |
66 | * <p> |
67 | * Accessed by native code. DO NOT RENAME THIS FIELD. |
68 | */ |
69 | private int lastErrorCode; |
70 | |
71 | /** |
72 | * The internal handle to the function and the module. |
73 | * <p> |
74 | * These are set in native code, so ignore any warnings. |
75 | * <p> |
76 | * Accessed by native code. DO NOT RENAME THIS FIELD. |
77 | */ |
78 | private int functionHandle, moduleHandle; |
79 | |
80 | /** |
81 | * The name of the function to call. |
82 | * <p> |
83 | * Accessed by native code. DO NOT RENAME THIS FIELD. |
84 | */ |
85 | private String function; |
86 | |
87 | /** |
88 | * The name of the module to call. |
89 | * <p> |
90 | * Accessed by native code. DO NOT RENAME THIS FIELD. |
91 | */ |
92 | private String module; |
93 | |
94 | /** |
95 | * Initialize JNI field and method IDs |
96 | */ |
97 | private static native void initIDs(); |
98 | |
99 | /** |
100 | * Whether the class has been initialized properly. |
101 | */ |
102 | private static boolean initialized = false; |
103 | |
104 | /** |
105 | * Before NativeCall may be used, this method must be called. |
106 | * It loads the native library, prepares JNI field and method IDs and loads |
107 | * the matching {@link Verifier}. |
108 | * <p> |
109 | * Multiple calls are ignored. |
110 | * |
111 | * @throws IOException if an IOException occured during unpacking of |
112 | * the native library |
113 | * @throws SecurityException if accessing system properties was forbidden |
114 | * by the {@link SecurityManager} |
115 | * @throws UnsatisfiedLinkError if the <code>NativeCall.dll</code> could |
116 | * not be found |
117 | * @throws sun.misc.ServiceConfigurationError |
118 | * @throws UnsupportedOperationException if no matching |
119 | * {@link Verifier} could be found |
120 | */ |
121 | public static synchronized void init() |
122 | throws |
123 | IOException, |
124 | SecurityException, |
125 | UnsatisfiedLinkError, |
126 | ServiceConfigurationError, |
127 | UnsupportedOperationException { |
128 | if (!initialized) { |
129 | Verifiers.init(); |
130 | if (Verifiers.getInstance() == null) { |
131 | throw new UnsupportedOperationException(); |
132 | } |
133 | new NativeLoader("NativeCall").load(); |
134 | initIDs(); |
135 | initialized = true; |
136 | } |
137 | } |
138 | |
139 | /** |
140 | * Constructor for NativeCall. |
141 | * |
142 | * @param function the name of the function to use, may not be |
143 | * <code>null</code> |
144 | * @throws IllegalArgumentException if the function could not be found |
145 | * @throws NullPointerException if function is <code>null</code> |
146 | * @see Verifier#getDefaultModule() |
147 | * @see NativeCall#NativeCall(String, String) |
148 | */ |
149 | public NativeCall(String function) |
150 | throws IllegalArgumentException, NullPointerException { |
151 | this(Verifiers.getInstance().getDefaultModule(), function); |
152 | } |
153 | |
154 | /** |
155 | * Constructor for NativeCall. |
156 | * |
157 | * @param module the name of the module the function is stored in, may be |
158 | * <code>null</code> |
159 | * @param function the name of the function to use, may not be |
160 | * <code>null</code> |
161 | * @throws IllegalArgumentException if the function could not be found |
162 | * @throws NullPointerException if function is <code>null</code> |
163 | */ |
164 | public NativeCall(String module, String function) |
165 | throws IllegalArgumentException, NullPointerException { |
166 | Verifier v = Verifiers.getInstance(); |
167 | this.function = v.verifyFunctionName(function); |
168 | this.module = v.verifyModuleName(module); |
169 | if (!initHandles()) { |
170 | if (lastErrorCode != 0) { |
171 | throw new IllegalArgumentException(getLastError()); |
172 | } |
173 | throw new IllegalArgumentException(); |
174 | } |
175 | } |
176 | |
177 | /** |
178 | * Attempts to acquire handles to the functions. Returns if these could be |
179 | * acquired. |
180 | * |
181 | * @return if the handles could be acquired |
182 | */ |
183 | private native boolean initHandles(); |
184 | |
185 | /** |
186 | * Returns the error code that was returned during the last method call or |
187 | * 0 if the last method call did not produce an error. |
188 | * |
189 | * @see #getLastError() |
190 | * @return the last error code or 0 |
191 | */ |
192 | public final int getLastErrorCode() { |
193 | return lastErrorCode; |
194 | } |
195 | |
196 | /** |
197 | * Returns a formatted String containing the last error code or |
198 | * <code>null</code> if the last call did not produce an error. |
199 | * |
200 | * @see #getLastErrorCode() |
201 | * @return a String or <code>null</code> if the last error code is 0 |
202 | */ |
203 | public final native String getLastError(); |
204 | |
205 | /** |
206 | * Releases acquired module handles. This method must be called if the |
207 | * instance is not used anymore. After this method is called, methods of this |
208 | * NativeCall Object cannot be called anymore. |
209 | * <p> |
210 | * <strong>Failure to call this method might result in memory leaks.</strong> |
211 | * <p> |
212 | * <em>Updates the error code field. See {@link #getLastError()}.</em> |
213 | */ |
214 | public native synchronized void destroy(); |
215 | |
216 | /** |
217 | * Checks the supplied Object array for illegal/unsupported types. |
218 | * <p> |
219 | * <strong>During the verification, the contents of the array might be |
220 | * changed.</strong> |
221 | * |
222 | * @param params the Object array, may be <code>null</code> |
223 | * @throws ClassCastException if the type of one argument is not supported |
224 | */ |
225 | protected void check(Object[] params) throws ClassCastException { |
226 | if (params == null) { |
227 | return; |
228 | } |
229 | for (int i = 0; i < params.length; ++i) { |
230 | checkParam(params[i]); |
231 | if (params[i] instanceof String) { |
232 | params[i] = |
233 | Verifiers.getInstance().handleString( |
234 | (String) params[i], |
235 | module, |
236 | function); |
237 | } |
238 | } |
239 | } |
240 | |
241 | /** |
242 | * Checks one Object for illegal/unsupported types. |
243 | * |
244 | * @param o the Object, may be <code>null</code> |
245 | * @throws ClassCastException if the type of one argument is not supported |
246 | */ |
247 | protected void checkParam(Object o) throws ClassCastException { |
248 | if (o == null |
249 | || o instanceof Boolean |
250 | || o instanceof Integer |
251 | || o instanceof byte[] |
252 | || o instanceof char[] |
253 | || o instanceof String) { |
254 | return; |
255 | } |
256 | if (o instanceof Holder) { |
257 | checkParam(((Holder) o).get()); |
258 | return; |
259 | } |
260 | throw new ClassCastException(o.getClass().getName()); |
261 | } |
262 | |
263 | /** |
264 | * Returns if this Object is equal to another Object. The other Object must |
265 | * be an instance of the same type as this Object. Also, both the module |
266 | * and the function field must be equal. |
267 | * |
268 | * @param obj the other Object |
269 | * @return if this and the other Object are equal |
270 | * @see java.lang.Object#equals(java.lang.Object) |
271 | */ |
272 | public boolean equals(Object obj) { |
273 | if (this == obj) { |
274 | return true; |
275 | } |
276 | if (!(obj instanceof NativeCall)) { |
277 | return false; |
278 | } |
279 | if (!getClass().getName().equals(obj.getClass().getName())) { |
280 | return false; |
281 | } |
282 | NativeCall c = (NativeCall) obj; |
283 | return module.equals(c.module) && function.equals(c.function); |
284 | } |
285 | |
286 | /** |
287 | * Returns the hashCode of this Object. The hashCode is computed by XOR'ing |
288 | * the hash codes of the function and the module names. |
289 | * |
290 | * @return the hashCode |
291 | * @see java.lang.Object#hashCode() |
292 | */ |
293 | public int hashCode() { |
294 | int out = function.hashCode(); |
295 | out ^= module.hashCode(); |
296 | return out; |
297 | } |
298 | |
299 | /** |
300 | * Calls {@link #destroy()}. |
301 | * |
302 | * @see java.lang.Object#finalize() |
303 | */ |
304 | protected void finalize() throws Throwable { |
305 | try { |
306 | destroy(); |
307 | } |
308 | finally { |
309 | super.finalize(); |
310 | // in case NativeCall is a subclass of a class other than Object |
311 | } |
312 | } |
313 | |
314 | /** |
315 | * Returns a String representation of this Object. |
316 | * |
317 | * @return a String, never <code>null</code> |
318 | * @see java.lang.Object#toString() |
319 | * @see #toStringBuffer(StringBuffer) |
320 | */ |
321 | public final String toString() { |
322 | return toStringBuffer(null).toString(); |
323 | } |
324 | |
325 | /** |
326 | * Appends a String representation of this Object to the given |
327 | * {@link StringBuffer} or creates a new one if none is given. |
328 | * |
329 | * @param in the StringBuffer to append to, may be <code>null</code> |
330 | * @return a StringBuffer, never <code>null</code> |
331 | */ |
332 | public StringBuffer toStringBuffer(StringBuffer in) { |
333 | if (in == null) { |
334 | in = new StringBuffer(64); |
335 | } |
336 | else { |
337 | in.ensureCapacity(in.length() + 64); |
338 | } |
339 | in.append("{ "); |
340 | int idx = getClass().getName().lastIndexOf("."); |
341 | if (idx > -1) { |
342 | in.append(getClass().getName().substring(++idx)); |
343 | } |
344 | else { |
345 | in.append(getClass().getName()); |
346 | } |
347 | in.append(": module = "); |
348 | in.append(module); |
349 | in.append(", function = "); |
350 | in.append(function); |
351 | in.append(" }"); |
352 | return in; |
353 | } |
354 | |
355 | } |