View Javadoc

1   /*
2   Copyright (C) 2000 - 2007 Grid Systems, S.A.
3   
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License, version 2, as
6   published by the Free Software Foundation.
7   
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12  
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  */
17  package com.gridsystems.utils;
18  
19  import java.io.File;
20  import java.io.FileOutputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  import com.gridsystems.utils.SystemUtils.OsMapEntry;
28  
29  /**
30   * Utility methods for JNI.
31   * @author Xmas
32   *
33   */
34  public final class JNIUtils {
35  
36    /** Maximum index to use to store libraries into disk. */
37    private static final int MAX_DYN_LIB_INDEX = 100;
38  
39    /**
40     * Logger instance for this class.
41     */
42    private static Log log = LogFactory.getLog(JNIUtils.class);
43  
44    /**
45     * Constructor.
46     */
47    private JNIUtils() {
48      super();
49    }
50  
51    /**
52     *  Return prefix and postfix of the dinamic libraries name in
53     *  the operating system 'os'.
54     *
55     *  @param os the operating system
56     *  @return A string array of lenght 2: position 0 contains prefix and
57     *          position 1 contains posfix of dinamic library.
58     */
59    public static String[] getNativePrefixPostfix(String os) {
60      if (os == null) {
61        return null;
62      }
63  
64      int pos = os.lastIndexOf("_");
65      String osPrefix = os.substring(0, pos);
66  
67      OsMapEntry entry = SystemUtils.MAP.get(osPrefix);
68      if (entry == null) {
69        log.error("Cannot find native prefix/postfix for OS " + os);
70        return null;
71      } else {
72        return entry.getLibPreSuffix();
73      }
74    }
75  
76    /**
77     * Extracts a Dynamic library of a jar file and load into memory.
78     * @param dynamiclibraryname the DL name
79     * @param pathclass the path class
80     * @return Path to file extracted.
81     * @throws Exception if error
82     */
83    public static File extractDynamicLibrary(String dynamiclibraryname,
84                                      Class< ? > pathclass) throws Exception {
85      String path = pathclass.getPackage().getName().replace('.', '/');
86      return extractDynamicLibrary(dynamiclibraryname, path);
87    }
88  
89    /**
90     * Extracts a Dynamic library of a jar file and loads it into memory.
91     * @param dynamiclibraryname the DL name
92     * @param path the path
93     * @return Path to file extracted.
94     * @throws Exception if error
95     */
96    public static File extractDynamicLibrary(
97      String dynamiclibraryname, String path) throws Exception {
98  
99      OsMapEntry entry = SystemUtils.getInternalEntry();
100     if (entry == null) {
101       // "There is not Dynamic Library Information for OS "+os
102       throw new Exception(I18n.translate("error.dll.noinfo", SystemUtils.getOsName()));
103     }
104 
105     String[] prefixes = entry.getLibPreSuffix();
106     File lib = null;
107     InputStream is;
108 
109     ClassLoader cl = Thread.currentThread().getContextClassLoader();
110     String libFile = prefixes[0] + dynamiclibraryname + prefixes[1];
111     String ruta = path + "/" + SystemUtils.getOsName() + "/" + libFile;
112 
113     int i = 0;
114     try {
115       File tmpDir = null;
116       if (SystemUtils.isWindows()) {
117         tmpDir = new File(SystemUtils.getTempDir());
118       } else {
119         tmpDir = new File(SystemUtils.getTempDir(), "xDynLib_" + System.nanoTime());
120         tmpDir.mkdir();
121         tmpDir.deleteOnExit();
122       }
123       while (true) {
124         lib = getDllTempFile(prefixes[0] + dynamiclibraryname, i, prefixes[1], tmpDir);
125         is = cl.getResourceAsStream(ruta);
126         if (is == null) {
127           // No encuentra el recurso demandado
128           throw new Exception(I18n.translate("error.resourcenotfound", ruta));
129         }
130 
131         boolean fileAlreadyExisted = lib.exists();
132 
133         boolean success = copyLibrary(lib, is, dynamiclibraryname);
134 
135         if (success) {
136           // If the JVM exits normally, the file will be deleted.
137           lib.deleteOnExit();
138           // The library was successfully stored.
139           if ("HP-UX".equals(entry.getName())) {
140             FileUtils.chmod("0555", lib, false);
141           }
142 
143           System.load(lib.getAbsolutePath());
144           return lib;
145         }
146         // From here, success = false
147         if (!fileAlreadyExisted) {
148           // If could not write the file and the file did not exist previously,
149           // then the failure is not due to a locked file
150           throw new Exception(I18n.translate("error.write.file"));
151         }
152         i++;
153         // Try with the next integer;
154         if (i > MAX_DYN_LIB_INDEX) {
155           throw new Exception(I18n.translate("error.dll.maxindex"));
156         }
157       }
158     } catch (Exception ex) {
159       String[] params = new String[]{dynamiclibraryname, ex.getMessage()};
160       String msg = I18n.translate("error.dll.load", params);
161       log.error(msg, ex);
162       throw new Exception(msg);
163     } finally {
164       if ((lib != null) && (SystemUtils.isUnix())) {
165         new File(lib.getParentFile().getAbsolutePath()).deleteOnExit();
166       }
167     }
168   }
169 
170   /**
171    * Gets a name where a dll will be tried to be saved.
172    *
173    * @param dllName the name of the library (not the file name).
174    * @param index the numbers of attempts previously failed.
175    * @param dllExtension the extension to assign to the file.
176    * @param tmpDir Temporal directory where store dll.
177    * @return the File to use to store the dll in disk.
178    */
179   private static File getDllTempFile(
180     String dllName, int index, String dllExtension, File tmpDir) {
181 
182     if (!tmpDir.exists()) {
183       System.err.println("TEMPORAL DIRECTORY " + tmpDir
184         + " DOES NOT EXIST! EXITING!");
185       System.out.println("TEMPORAL DIRECTORY " + tmpDir
186         + " DOES NOT EXIST! EXITING!");
187       log.fatal("TEMPORAL DIRECTORY " + tmpDir + " DOES NOT EXIST!");
188       System.exit(-1);
189     }
190     String systemUser = System.getProperty("user.name", "none");
191     String newFileName = null;
192     if (index == 0) {
193       newFileName = dllName + "_" + systemUser + dllExtension;
194     } else {
195       newFileName = dllName + "_" + systemUser + "_" + index + dllExtension;
196     }
197     return new File(tmpDir, newFileName);
198   }
199 
200   /**
201    * Copies a file from a InputStream to a file in disk.
202    *
203    * @param dst the destination file.
204    * @param is the inputstream from which read. This method will close it.
205    * @param name the name of the library being copied (for log purposes).
206    *
207    * @return true if and only if the file was successfully copied, and false if
208    * an error happened when writting to the new file.
209    * @throws IOException if an error happened when reading from the is.
210    */
211   private static boolean copyLibrary(File dst, InputStream is, String name)
212     throws IOException {
213     // If after storing the file this flag is still false, the file was
214     // successfully stored
215     FileOutputStream fos = null;
216     try {
217       try {
218         fos = new FileOutputStream(dst);
219       } catch (IOException ioe) {
220         log.info("Could not open outputstream to " + dst);
221         return false;
222       }
223 
224       int length;
225       byte[] datos = new byte[FileUtils.ONE_KB_IN_BYTES];
226       while ((length = is.read(datos)) != -1) {
227         try {
228           fos.write(datos, 0, length);
229         } catch (IOException ioe) {
230           log.warn("Could not extract the " + name + " to " + dst, ioe);
231           return false;
232         }
233       }
234     } finally {
235       try {
236         is.close();
237       } catch (Exception e) {
238         log.warn("Exception closing InputStream from classloader");
239       }
240       try {
241         fos.close();
242       } catch (Exception e) {
243         log.warn("Exception closing OutputStream from classloader");
244       }
245     }
246     return true;
247   }
248 
249 }