View Javadoc

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