View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2006-2008 Vlad Skarzhevskyy
4    *
5    *  Licensed to the Apache Software Foundation (ASF) under one
6    *  or more contributor license agreements.  See the NOTICE file
7    *  distributed with this work for additional information
8    *  regarding copyright ownership.  The ASF licenses this file
9    *  to you under the Apache License, Version 2.0 (the
10   *  "License"); you may not use this file except in compliance
11   *  with the License.  You may obtain a copy of the License at
12   *
13   *    http://www.apache.org/licenses/LICENSE-2.0
14   *
15   *  Unless required by applicable law or agreed to in writing,
16   *  software distributed under the License is distributed on an
17   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18   *  KIND, either express or implied.  See the License for the
19   *  specific language governing permissions and limitations
20   *  under the License.
21   *
22   *  @author vlads
23   *  @version $Id: NativeLibLoader.java 2476 2008-12-01 17:41:59Z skarzhevskyy $
24   */
25  package com.intel.bluetooth;
26  
27  import java.io.File;
28  import java.io.FileOutputStream;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.util.Hashtable;
32  
33  import com.ibm.oti.vm.VM;
34  
35  /**
36   * Load native library from resources.
37   *
38   *
39   * By default Native Library is extracted from from jar to temporary directory
40   * `${java.io.tmpdir}/bluecove_${user.name}_N` and loaded from this location.
41   * <p>
42   * If you wish to load library (.dll) from another location add this system
43   * property `-Dbluecove.native.path=/your/path`.
44   * <p>
45   * If you wish to load library from default location in path e.g.
46   * `%SystemRoot%\system32` or any other location in %PATH% use
47   * `-Dbluecove.native.resource=false`
48   *
49   */
50  public abstract class NativeLibLoader {
51  
52  	static final int OS_UNSUPPORTED = -1;
53  
54  	static final int OS_LINUX = 1;
55  
56  	static final int OS_WINDOWS = 2;
57  
58  	static final int OS_WINDOWS_CE = 3;
59  
60  	static final int OS_MAC_OS_X = 4;
61  
62  	private static int os = 0;
63  
64  	private static Hashtable libsState = new Hashtable();
65  
66  	private static String bluecoveDllDir = null;
67  
68  	private static class LibState {
69  
70  		boolean triedToLoadAlredy = false;
71  
72  		boolean libraryAvailable = false;
73  
74  	}
75  
76  	private NativeLibLoader() {
77  
78  	}
79  
80  	static int getOS() {
81  		if (os != 0) {
82  			return os;
83  		}
84  		String sysName = System.getProperty("os.name");
85  		if (sysName == null) {
86  			DebugLog.fatal("Native Library not available on unknown platform");
87  			os = OS_UNSUPPORTED;
88  		} else {
89  			sysName = sysName.toLowerCase();
90  			if (sysName.indexOf("windows") != -1) {
91  				if (sysName.indexOf("ce") != -1) {
92  					os = OS_WINDOWS_CE;
93  				} else {
94  					os = OS_WINDOWS;
95  				}
96  			} else if (sysName.indexOf("mac os x") != -1) {
97  				os = OS_MAC_OS_X;
98  			} else if (sysName.indexOf("linux") != -1) {
99  				os = OS_LINUX;
100 			} else {
101 				DebugLog.fatal("Native Library not available on platform " + sysName);
102 				os = OS_UNSUPPORTED;
103 			}
104 		}
105 		return os;
106 	}
107 
108 	static boolean isAvailable(String name) {
109 		return isAvailable(name, null);
110 	}
111 
112 	static boolean isAvailable(String name, Class stackClass) {
113 		LibState state = (LibState) libsState.get(name);
114 		if (state == null) {
115 			state = new LibState();
116 			libsState.put(name, state);
117 		}
118 		if (state.triedToLoadAlredy) {
119 			return state.libraryAvailable;
120 		}
121 		String libName = name;
122 		String libFileName = libName;
123 
124 		// DebugLog.debug("OS:" + System.getProperty("os.name") + "|" +
125 		// System.getProperty("os.version") + "|" +
126 		// System.getProperty("os.arch"));
127 		// DebugLog.debug("Java:" + System.getProperty("java.vendor") + " " +
128 		// System.getProperty("java.version"));
129 
130 		String sysName = System.getProperty("os.name");
131 
132 		String sysArch = System.getProperty("os.arch");
133 		if (sysArch != null) {
134 			sysArch = sysArch.toLowerCase();
135 		} else {
136 			sysArch = "";
137 		}
138 
139 		switch (getOS()) {
140 		case OS_UNSUPPORTED:
141 			DebugLog.fatal("Native Library " + name + " not available on [" + sysName + "] platform");
142 			state.triedToLoadAlredy = true;
143 			state.libraryAvailable = false;
144 			return state.libraryAvailable;
145 		case OS_WINDOWS_CE:
146 			libName += "_ce";
147 			libFileName = libName;
148 			libFileName = libFileName + ".dll";
149 			break;
150 		case OS_WINDOWS:
151 			if ((sysArch.indexOf("amd64") != -1) || (sysArch.indexOf("x86_64") != -1)) {
152 				libName += "_x64";
153 				libFileName = libName;
154 			}
155 			libFileName = libFileName + ".dll";
156 			break;
157 		case OS_MAC_OS_X:
158 			libFileName = "lib" + libFileName + ".jnilib";
159 			break;
160 		case OS_LINUX:
161 			if ((sysArch.indexOf("i386") != -1) || (sysArch.length() == 0)) {
162 				// regular Intel
163 			} else if ((sysArch.indexOf("amd64") != -1) || (sysArch.indexOf("x86_64") != -1)) {
164 				libName += "_x64";
165 			} else if ((sysArch.indexOf("x86") != -1)) {
166 				// regular Intel under IBM J9
167 			} else {
168 				// Any other system
169 				libName += "_" + sysArch;
170 			}
171 			libFileName = libName;
172 			libFileName = "lib" + libFileName + ".so";
173 			break;
174 		default:
175 			DebugLog.fatal("Native Library " + name + " not available on platform " + sysName);
176 			state.triedToLoadAlredy = true;
177 			state.libraryAvailable = false;
178 			return state.libraryAvailable;
179 		}
180 
181 		String path = System.getProperty(BlueCoveConfigProperties.PROPERTY_NATIVE_PATH);
182 		if (path != null) {
183 			if (!UtilsJavaSE.ibmJ9midp) {
184 				state.libraryAvailable = tryloadPath(path, libFileName);
185 			} else {
186 				// Not working
187 				// state.libraryAvailable = tryloadPathIBMj9MIDP(path,
188 				// libFileName);
189 			}
190 		}
191 		boolean useResource = true;
192 		String d = System.getProperty(BlueCoveConfigProperties.PROPERTY_NATIVE_RESOURCE);
193 		if ((d != null) && (d.equalsIgnoreCase("false"))) {
194 			useResource = false;
195 		}
196 
197 		if ((!state.libraryAvailable) && (useResource) && (!UtilsJavaSE.ibmJ9midp)) {
198 			state.libraryAvailable = loadAsSystemResource(libFileName, stackClass);
199 		}
200 		if (!state.libraryAvailable) {
201 			if (!UtilsJavaSE.ibmJ9midp) {
202 				state.libraryAvailable = tryload(libName);
203 			} else {
204 				state.libraryAvailable = tryloadIBMj9MIDP(libName);
205 			}
206 		}
207 
208 		if (!state.libraryAvailable) {
209 			System.err.println("Native Library " + libName + " not available");
210 			DebugLog.debug("java.library.path", System.getProperty("java.library.path"));
211 		}
212 		state.triedToLoadAlredy = true;
213 		return state.libraryAvailable;
214 	}
215 
216 	private static boolean tryload(String name) {
217 		try {
218 			System.loadLibrary(name);
219 			DebugLog.debug("Library loaded", name);
220 		} catch (Throwable e) {
221 			DebugLog.error("Library " + name + " not loaded ", e);
222 			return false;
223 		}
224 		return true;
225 	}
226 
227 	private static boolean tryloadIBMj9MIDP(String name) {
228 		try {
229 			VM.loadLibrary(name);
230 			DebugLog.debug("Library loaded", name);
231 		} catch (Throwable e) {
232 			DebugLog.error("Library " + name + " not loaded ", e);
233 			return false;
234 		}
235 		return true;
236 	}
237 
238 	private static boolean tryloadPath(String path, String name) {
239 		try {
240 			File f = new File(path, name);
241 			if (!f.canRead()) {
242 				DebugLog.fatal("Native Library " + f.getAbsolutePath() + " not found");
243 				return false;
244 			}
245 			System.load(f.getAbsolutePath());
246 			DebugLog.debug("Library loaded", f.getAbsolutePath());
247 		} catch (Throwable e) {
248 			DebugLog.error("Can't load library from path " + path, e);
249 			return false;
250 		}
251 		return true;
252 	}
253 
254 	private static boolean tryloadPathIBMj9MIDP(String path, String name) {
255 		try {
256 			VM.loadLibrary(path + "\\" + name);
257 			DebugLog.debug("Library loaded", path + "\\" + name);
258 		} catch (Throwable e) {
259 			DebugLog.error("Can't load library from path " + path + "\\" + name, e);
260 			return false;
261 		}
262 		return true;
263 	}
264 
265 	private static boolean loadAsSystemResource(String libFileName, Class stackClass) {
266 		InputStream is = null;
267 		try {
268 			ClassLoader clo = null;
269 			try {
270 				if (stackClass != null) {
271 					clo = stackClass.getClassLoader();
272 					DebugLog.debug("Use stack ClassLoader");
273 				} else {
274 					clo = NativeLibLoader.class.getClassLoader();
275 				}
276 			} catch (Throwable j9) {
277 			}
278 			if (clo == null) {
279 				DebugLog.debug("Use System ClassLoader");
280 				is = ClassLoader.getSystemResourceAsStream(libFileName);
281 			} else {
282 				is = clo.getResourceAsStream(libFileName);
283 			}
284 		} catch (Throwable e) {
285 			DebugLog.error("Native Library " + libFileName + " is not a Resource !");
286 			return false;
287 		}
288 		if (is == null) {
289 			DebugLog.error("Native Library " + libFileName + " is not a Resource !");
290 			return false;
291 		}
292 		File fd = makeTempName(libFileName);
293 		try {
294 			if (!copy2File(is, fd)) {
295 				return false;
296 			}
297 		} finally {
298 			try {
299 				is.close();
300 			} catch (IOException ignore) {
301 				is = null;
302 			}
303 		}
304 		try {
305 			fd.deleteOnExit();
306 		} catch (Throwable e) {
307 			// Java 1.1 or J9
308 		}
309 		// deleteOnExit(fd);
310 		try {
311 			System.load(fd.getAbsolutePath());
312 			DebugLog.debug("Library loaded from", fd);
313 		} catch (Throwable e) {
314 			DebugLog.error("Can't load library file ", e);
315 			return false;
316 		}
317 		return true;
318 	}
319 
320 	private static boolean copy2File(InputStream is, File fd) {
321 		FileOutputStream fos = null;
322 		try {
323 			fos = new FileOutputStream(fd);
324 			byte b[] = new byte[1000];
325 			int len;
326 			while ((len = is.read(b)) >= 0) {
327 				fos.write(b, 0, len);
328 			}
329 			return true;
330 		} catch (Throwable e) {
331 			DebugLog.debug("Can't create temporary file ", e);
332 			System.err.println("Can't create temporary file " + fd.getAbsolutePath());
333 			return false;
334 		} finally {
335 			if (fos != null) {
336 				try {
337 					fos.close();
338 				} catch (IOException ignore) {
339 					fos = null;
340 				}
341 			}
342 		}
343 	}
344 
345 	private static File makeTempName(String libFileName) {
346 		if (bluecoveDllDir != null) {
347 			return new File(bluecoveDllDir, libFileName);
348 		}
349 		String tmpDir = System.getProperty("java.io.tmpdir");
350 		String uname = System.getProperty("user.name");
351 		int count = 0;
352 		File fd = null;
353 		File dir = null;
354 		selectDirectory: while (true) {
355 			if (count > 10) {
356 				DebugLog.debug("Can't create temporary dir " + dir.getAbsolutePath());
357 				return new File(tmpDir, libFileName);
358 			}
359 			dir = new File(tmpDir, "bluecove_" + uname + "_" + (count++));
360 			if (dir.exists()) {
361 				if (!dir.isDirectory()) {
362 					continue selectDirectory;
363 				}
364 				// Remove all files.
365 				try {
366 					File[] files = dir.listFiles();
367 					for (int i = 0; i < files.length; i++) {
368 						if (!files[i].delete()) {
369 							continue selectDirectory;
370 						}
371 					}
372 				} catch (Throwable e) {
373 					// Java 1.1 or J9
374 				}
375 			}
376 			if ((!dir.exists()) && (!dir.mkdirs())) {
377 				DebugLog.debug("Can't create temporary dir ", dir.getAbsolutePath());
378 				continue selectDirectory;
379 			}
380 			try {
381 				dir.deleteOnExit();
382 			} catch (Throwable e) {
383 				// Java 1.1 or J9
384 			}
385 			fd = new File(dir, libFileName);
386 			if ((fd.exists()) && (!fd.delete())) {
387 				continue;
388 			}
389 			try {
390 				if (!fd.createNewFile()) {
391 					DebugLog.debug("Can't create file in temporary dir ", fd.getAbsolutePath());
392 					continue;
393 				}
394 			} catch (IOException e) {
395 				DebugLog.debug("Can't create file in temporary dir ", fd.getAbsolutePath());
396 				continue;
397 			} catch (Throwable e) {
398 				// Java 1.1 or J9
399 			}
400 			bluecoveDllDir = dir.getAbsolutePath();
401 			break;
402 		}
403 		return fd;
404 	}
405 
406 	// private static void deleteOnExit(final File fd) {
407 	// Runnable r = new Runnable() {
408 	// public void run() {
409 	// if (!fd.delete()) {
410 	// System.err.println("Can't remove Native Library " + fd);
411 	// }
412 	// }
413 	// };
414 	// Runtime.getRuntime().addShutdownHook(new Thread(r));
415 	// }
416 
417 }