001: package net.xoetrope.os;
002:
003: import java.io.File;
004: import java.io.FileOutputStream;
005: import java.io.IOException;
006: import java.io.InputStream;
007: import java.net.URL;
008: import java.util.Hashtable;
009: import java.util.jar.JarEntry;
010: import java.util.jar.JarFile;
011: import java.io.BufferedInputStream;
012: import java.io.FileInputStream;
013:
014: /** Loads a native library file. The class can load the library by attempting to
015: * have the Sytem class load the library from the library path. If this fails the
016: * class can attempt to load the file by extracting it from the classpath,
017: * including the Jar files on the classpath and then loading it with the full
018: * file path. A temporary directory is used to temporarily extract the file.
019: * If the file is loaded successfully the library name is placed in a hashtable
020: * so that subsequent calls to load the library to not actually attempt to
021: * load the library.
022: *
023: * <p> Copyright (c) Xoetrope Ltd., 2002-2004</p>
024: * <p> $Revision: 1.8 $</p>
025: * <p> License: see License.txt</p>
026: */
027: public class LibraryLoader {
028: protected final static int BUF_LEN = 4096;
029: protected static String extractDir = null;
030: private static Hashtable loadedResources = new Hashtable();
031: private static long sourceModDate = 0l;
032:
033: public static void load(ClassLoader clazz, String resName) {
034: LibraryLoader ll = new LibraryLoader();
035: ll.load(clazz, resName, true, false);
036: }
037:
038: public static String extractFile(ClassLoader classLoader,
039: String resName) throws IOException {
040: LibraryLoader ll = new LibraryLoader();
041: return ll.extractFile(classLoader, resName, false);
042: }
043:
044: /**
045: * Load a native library
046: * @param classLoader the classLoader used to find the library/resource
047: * @param resName the library/resource name
048: * @param checkLibPath true to check the system library path first before checking the resource path
049: * @param overwrite true to overwrite any existing temporary file, if false the the timestamp is checked to see
050: * if the file needs to be extracted to the temporary directory
051: */
052: public void load(ClassLoader classLoader, String resName,
053: boolean checkLibPath, boolean overwrite) {
054: if (loadedResources.get(resName) == null) {
055: boolean loadedFromSystem = checkLibPath;
056: if (checkLibPath) {
057: // Attempt to load the library from the system library path
058: try {
059: System.load(resName);
060: } catch (SecurityException sec) {
061: loadedFromSystem = false;
062: } catch (UnsatisfiedLinkError ul) {
063: loadedFromSystem = false;
064: }
065: }
066:
067: try {
068: // If the file is not loaded then try extracting it tp a temporary file and
069: // loading it directly
070: if (!loadedFromSystem) {
071: extractFile(classLoader, resName, overwrite);
072: System.load(getExtractDirectory() + resName);
073: }
074:
075: // Save the resource name so that it is not reloaded
076: loadedResources.put(resName, resName);
077: } catch (IOException ex) {
078: ex.printStackTrace();
079: }
080: }
081: }
082:
083: /**
084: * Get the directory name to which the library will be extracted.
085: * @return the path
086: */
087: protected String getExtractDirectory() {
088: if (extractDir == null) {
089: try {
090: File tempFile = File.createTempFile("xui", ".dll");
091: String path = tempFile.getPath();
092: extractDir = path.substring(0, path
093: .lastIndexOf(File.separatorChar) + 1);
094:
095: tempFile.delete();
096: } catch (IOException ex) {
097: }
098: }
099: return extractDir;
100: }
101:
102: /**
103: * Check that the temporary file exists and is up-to-date
104: * @param url the URL of the source file
105: * @param targetFile the temporary file
106: * @return true if the file exists and is up-to-date
107: */
108: protected boolean isUpToDate(URL url, File targetFile) {
109: try {
110: long targetModDate = 0l;
111: sourceModDate = 0l;
112:
113: if (targetFile.exists()) {
114: targetModDate = targetFile.lastModified();
115: } else {
116: return false; // The file does not exist
117: }
118:
119: String path = url.getFile();
120: // For a Jar file the path will be something like c:\tmp\myjar.jar!/mypackage/mydll.dll
121: if (path.indexOf(".jar") > 0) {
122: path = path.substring(6);
123: int separatorPos = path.indexOf('!');
124:
125: // Skip the first forward slash
126: String searchPath = path.substring(separatorPos + 2);
127: searchPath = searchPath.replace('\\', '/');
128: JarFile jf = new JarFile(path
129: .substring(0, separatorPos));
130: JarEntry je = jf.getJarEntry(searchPath);
131: sourceModDate = je.getTime();
132: } else {
133: File _file = new File(url.getFile());
134: sourceModDate = _file.lastModified();
135: }
136:
137: // For the same version of the file the dates should match
138: return (sourceModDate == targetModDate);
139: } catch (IOException ex) {
140: return false;
141: }
142: }
143:
144: /**
145: * Extract a file from a jar file to the specified location
146: * @param classLoader the classloder to use to load the file
147: * @param overwrite true to overwrite any existing file
148: * @param resName the resource to extract
149: * @return the path to which the file is extracted
150: * @throws IOException
151: */
152: public String extractFile(ClassLoader classLoader, String resName,
153: boolean overwrite) throws IOException {
154: URL url = classLoader.getResource(resName);
155: String targetPath = getExtractDirectory() + resName;
156: File targetFile = new File(targetPath);
157: if (!overwrite && (url != null))
158: overwrite = !isUpToDate(url, targetFile);
159:
160: if (overwrite) {
161: FileOutputStream fos = new FileOutputStream(targetFile);
162:
163: InputStream is = classLoader.getResource(resName)
164: .openStream();
165: byte[] c = new byte[BUF_LEN];
166:
167: int i = 1;
168: String result = new String("");
169: while (i != -1) {
170: i = is.read(c, 0, BUF_LEN);
171: if (i > 0) {
172: fos.write(c, 0, i);
173: }
174: }
175:
176: fos.flush();
177: fos.close();
178:
179: // Set the last moified file date
180: targetFile.setLastModified(sourceModDate);
181: }
182:
183: return targetPath;
184: }
185: }
|