/src-plugins/3D_Viewer/ij3d/Install_J3D.java

https://github.com/hgrecco/fiji · Java · 432 lines · 295 code · 47 blank · 90 comment · 43 complexity · c9c4928eda6e58721fde75ec71ffbd2c MD5 · raw file

  1. package ij3d;
  2. import ij.plugin.PlugIn;
  3. import ij.gui.YesNoCancelDialog;
  4. import ij.IJ;
  5. import java.net.URL;
  6. import java.net.URLConnection;
  7. import java.net.MalformedURLException;
  8. import java.awt.Frame;
  9. import java.util.zip.*;
  10. import java.util.Enumeration;
  11. import java.util.List;
  12. import java.util.ArrayList;
  13. import java.io.BufferedReader;
  14. import java.io.InputStreamReader;
  15. import java.io.FileNotFoundException;
  16. import java.io.IOException;
  17. import java.io.InputStream;
  18. import java.io.File;
  19. import java.io.FileOutputStream;
  20. import java.io.ByteArrayOutputStream;
  21. import javax.media.j3d.VirtualUniverse;
  22. public class Install_J3D implements PlugIn {
  23. /** Base URL to the folder containing the Java3D files */
  24. private static final String JAVA3D_BASE_URL =
  25. "http://132.187.25.13/java3d/";
  26. /** Base URL to the folder containing the Jogl files */
  27. private static final String JOGL_BASE_URL =
  28. "http://download.java.net/media/jogl/builds/archive/jsr-231-1.1.1/";
  29. /** File name of the 32-bit windows version of Java3D */
  30. private static final String WIN_32 = "j3d-1_5_2-windows-i586.zip";
  31. /** File name of the 64-bit windows version of Java3D */
  32. private static final String WIN_64 = "j3d-1_5_2-windows-amd64.zip";
  33. /** File name of the 32-bit linux version of Java3D */
  34. private static final String LIN_32 = "j3d-1_5_2-linux-i586.zip";
  35. /** File name of the 64-bit linux version of Java3D */
  36. private static final String LIN_64 = "j3d-1_5_2-linux-amd64.zip";
  37. /** File name of the mac osx version of Java3D */
  38. private static final String MAC = "j3d-1_5_2-macosx.zip";
  39. /** File name of the mac osx version for power pc of Jogl */
  40. private static final String JOGL_PPC = "jogl-1.1.1-macosx-ppc.zip";
  41. /** File name of the mac osx version for intel macs of Jogl */
  42. private static final String JOGL_ITL = "jogl-1.1.1-macosx-universal.zip";
  43. /** Temporary directory */
  44. private static final String TMP = System.getProperty("java.io.tmpdir");
  45. /** Java home directory */
  46. private static final String JRE = System.getProperty("java.home");
  47. /** Overwrite without asking for confirmation? */
  48. protected static boolean overwrite = false;
  49. /**
  50. * Run the installation stand-alone.
  51. */
  52. public static void main(String[] args) {
  53. overwrite = true;
  54. if (!new Install_J3D().autoInstall())
  55. System.exit(1);
  56. }
  57. /**
  58. * Run the installation as a plugin.
  59. */
  60. public void run(String arg) {
  61. autoInstall();
  62. }
  63. /**
  64. * Returns the Java3D specification version, as returned by
  65. * Universe.getProperty("j3d.specification.version"), or null
  66. * if the universe class can not be loaded.
  67. */
  68. public static String getJava3DVersion() {
  69. try {
  70. Class.forName("javax.media.j3d.VirtualUniverse");
  71. } catch(ClassNotFoundException e) {
  72. return null;
  73. }
  74. VirtualUniverse univ = new VirtualUniverse();
  75. return (String)univ.getProperties().
  76. get("j3d.specification.version");
  77. }
  78. /**
  79. * Detects the operating system and accordingly downloads the
  80. * needed Java3D files and extracts them.
  81. * In case of windows and linux, the j3djre.zip file, which is
  82. * contained in the downloaded archive, is simply extracted in
  83. * the java.home directory.
  84. * In case of mac, the j3djre.zip is extracted into a temporary
  85. * directory, and the jar files are then moved to the 1st folder
  86. * as returned by System.getProperty("java.ext.dirs").
  87. *
  88. * On Mac, Jogl has to be installed, in addition to Java3D.
  89. * Depending on the architecture, the corresponding files are
  90. * downloaded and extracted, as the files of j3djre.zip, to
  91. * the 1st extension directory of java.
  92. *
  93. * @return true on success
  94. */
  95. public static boolean autoInstall() {
  96. String filename = null;
  97. if(IJ.isLinux())
  98. filename = IJ.is64Bit() ? LIN_64 : LIN_32;
  99. else if(IJ.isWindows())
  100. filename = IJ.is64Bit() ? WIN_64 : WIN_32;
  101. else if(IJ.isMacOSX())
  102. filename = MAC;
  103. if(filename == null) {
  104. println("could not detect operating system");
  105. return false;
  106. }
  107. try {
  108. installJava3D(filename);
  109. if(IJ.isMacOSX()) {
  110. filename = isPPC() ? JOGL_PPC : JOGL_ITL;
  111. installJogl(filename);
  112. }
  113. } catch(Exception e) {
  114. IJ.error(e.getMessage());
  115. println(e.getMessage());
  116. e.printStackTrace();
  117. return false;
  118. }
  119. print("Installation successful!");
  120. return true;
  121. }
  122. /**
  123. * Returns true if running on a Power PC.
  124. */
  125. public static boolean isPPC() {
  126. String arch = System.getProperty("os.arch");
  127. if(arch.startsWith("ppc"))
  128. return true;
  129. return false;
  130. }
  131. /**
  132. * Downloads the given file from the JOGL homepage and extracts
  133. * the contained jnilibs to the first directory as returned by
  134. * System.getProperty("java.ext.dirs").
  135. */
  136. public static void installJogl(String zipname) throws Exception {
  137. println("Detecting Mac OS X operating system, installing Jogl");
  138. File downloaded = download(JOGL_BASE_URL + zipname);
  139. File tempdir = createFolder(TMP, "jogl", false);
  140. List<File> files = unzip(downloaded, tempdir, null);
  141. String extdir = getFirstExtDir();
  142. if(!new File(extdir).exists())
  143. new File(extdir).mkdirs();
  144. if(!new File(extdir).canWrite())
  145. throw new Exception("No permissions to write to " + extdir);
  146. for(File file : files) {
  147. if(!file.getName().endsWith(".jar") &&
  148. !file.getName().endsWith(".jnilib"))
  149. continue;
  150. File dst = new File(extdir, file.getName());
  151. println("moving " + file.getAbsolutePath() +
  152. " to " + dst.getAbsolutePath());
  153. if(!file.renameTo(dst)) {
  154. println("could not move " + file.getAbsolutePath() +
  155. " to " + dst.getAbsolutePath());
  156. }
  157. }
  158. rm(tempdir);
  159. }
  160. public static String getFirstExtDir() throws Exception {
  161. String extdirs = System.getProperty("java.ext.dirs");
  162. if(extdirs == null)
  163. throw new Exception("Can't detect java extension directory");
  164. return extdirs.split(File.pathSeparator)[0];
  165. }
  166. /**
  167. * Downloads the given file from the Java3D homepage and extracts
  168. * the contained j3d-jre.zip to a temporary directory.
  169. * In case of Linux or Windows, this file is afterwards extracted
  170. * in the java.home folder.
  171. * In case of MacOSX it is extracted to a temporary folder, and the
  172. * jar files are then moved to the first folder returned by
  173. * System.getProperty("java.ext.dirs").
  174. */
  175. public static void installJava3D(String zipname) throws Exception {
  176. File downloaded = download(JAVA3D_BASE_URL + zipname);
  177. File tempdir = createFolder(TMP, "java3d", false);
  178. List<File> files = unzip(downloaded, tempdir, "j3d-jre.zip");
  179. if(files.size() == 0)
  180. throw new Exception("Could not find j3d-jre.zip in "
  181. + downloaded);
  182. File j3djre = (File)files.get(0);
  183. /*
  184. * if not on a Mac, the j3djre zip file can just be extracted
  185. * in java.home.
  186. */
  187. if(!IJ.isMacOSX()) {
  188. files = unzip(j3djre, new File(JRE), null);
  189. return;
  190. }
  191. /*
  192. * On a Mac, we extract the zip file to a temporary folder and
  193. * move the contents afterwards in Mac's first java.ext folder.
  194. */
  195. files = unzip(j3djre, tempdir, null);
  196. String extdir = getFirstExtDir();
  197. if(!new File(extdir).exists())
  198. new File(extdir).mkdirs();
  199. println("Found java extension folder: " + extdir);
  200. if(!new File(extdir).canWrite())
  201. throw new Exception("No permissions to write to " + extdir);
  202. for(File file : files) {
  203. File dst = new File(extdir, file.getName());
  204. println("moving " + file.getAbsolutePath() +
  205. " to " + dst.getAbsolutePath());
  206. if(!file.renameTo(dst)) {
  207. println("could not move " + file.getAbsolutePath() +
  208. " to " + dst.getAbsolutePath());
  209. }
  210. }
  211. rm(tempdir);
  212. }
  213. /**
  214. * Create a folder with the given name in the given directory.
  215. * @param dir The directory in which the folder should be created.
  216. * @param name The name of the folder to be created.
  217. * @param failIfExists Flag to indicate whether to fail (throw an
  218. * Exception) if the folder exists already. If this is false, and
  219. * the folder exists, nothing will be done.
  220. */
  221. public static File createFolder(
  222. String dir, String name, boolean failIfExists) throws Exception {
  223. println("create folder " + dir + "/" + name);
  224. File directory = new File(dir);
  225. if(!directory.exists())
  226. directory.mkdirs();
  227. if(!directory.canWrite())
  228. throw new Exception(
  229. "No permissions to write to folder " + dir);
  230. File f = new File(dir, name);
  231. if(!f.exists()) {
  232. if(!f.mkdir()) {
  233. throw new Exception("Can't create directory "
  234. + f.getAbsolutePath());
  235. }
  236. return f;
  237. }
  238. if(failIfExists) {
  239. throw new Exception("Can't create directory "
  240. + f.getAbsolutePath()
  241. + ": File exists already");
  242. }
  243. println(f.getAbsolutePath() + " not created; exists already");
  244. return f;
  245. }
  246. /**
  247. * Download the file given by the specified url to a tmp folder.
  248. * Returns a reference to the downloaded file.
  249. */
  250. public static File download(String u) throws Exception {
  251. print("downloading " + u);
  252. InputStream is = null;
  253. URL url = null;
  254. try {
  255. url = new URL(u);
  256. URLConnection conn = url.openConnection();
  257. is = conn.getInputStream();
  258. } catch(MalformedURLException e1) {
  259. throw new Exception(u + " is not a valid URL");
  260. } catch(IOException e1) {
  261. throw new Exception("Can't open connection to " + u);
  262. }
  263. byte[] content = readFully(is);
  264. File out = new File(TMP, new File(url.getFile()).getName());
  265. println(" to " + out.getAbsolutePath());
  266. FileOutputStream fos = null;
  267. try {
  268. fos = new FileOutputStream(out);
  269. fos.write(content);
  270. fos.close();
  271. } catch(FileNotFoundException e1) {
  272. throw new Exception("Could not open "
  273. + out.getAbsolutePath() + " for writing. "
  274. + "Maybe not enough permissions?");
  275. } catch(IOException e2) {
  276. throw new Exception("Error writing to "
  277. + out.getAbsolutePath());
  278. }
  279. return out;
  280. }
  281. /**
  282. * Extracts fileToExtract from the zipfile in the specified directory.
  283. * If a file which is about to be extracted exists already, the user
  284. * is prompted asking whether to overwrite or skip.
  285. * Returns a List with the extracted files.
  286. */
  287. public static List<File> unzip(
  288. File zipfile, File dir, String fileToExtract) throws Exception {
  289. println("Extracting " + (fileToExtract != null ? fileToExtract
  290. : "all") + " to " + dir.getAbsolutePath());
  291. if(!dir.canWrite())
  292. throw new Exception(
  293. "No permissions to write to folder " + dir);
  294. ZipFile zfile = null;
  295. try {
  296. zfile = new ZipFile(zipfile);
  297. } catch(ZipException e) {
  298. throw new Exception(zipfile.getAbsolutePath() +
  299. " is not a valid zip file.");
  300. }
  301. Enumeration en = zfile.entries();
  302. List<File> extracted = new ArrayList<File>();
  303. while(en.hasMoreElements()) {
  304. ZipEntry ze = (ZipEntry)en.nextElement();
  305. if(ze.isDirectory()) {
  306. File newDir = createFolder(
  307. dir.getAbsolutePath(), ze.getName(), false);
  308. } else if(fileToExtract == null ||
  309. ze.getName().endsWith(fileToExtract)) {
  310. println("Extracting " + ze.getName() + " to " + dir);
  311. InputStream is = null;
  312. try {
  313. is = zfile.getInputStream(ze);
  314. } catch(IOException e) {
  315. throw new Exception(
  316. "Can't extract " + ze.getName());
  317. }
  318. byte[] content = readFully(is);
  319. File ext = new File(dir, ze.getName());
  320. if(!overwrite(ext))
  321. continue;
  322. try {
  323. FileOutputStream out = new FileOutputStream(ext);
  324. out.write(content);
  325. out.flush();
  326. out.close();
  327. } catch(FileNotFoundException e) {
  328. throw new Exception("Could not open "
  329. + ext.getAbsolutePath() + " for writing. "
  330. + "Maybe not enough permissions?");
  331. } catch(IOException e) {
  332. throw new Exception("Error writing to "
  333. + ext.getAbsolutePath());
  334. }
  335. extracted.add(ext);
  336. }
  337. }
  338. return extracted;
  339. }
  340. /**
  341. * Reads all bytes from the given InputStream and returns it as a
  342. * byte array.
  343. */
  344. public static byte[] readFully(InputStream is) throws Exception {
  345. ByteArrayOutputStream buf = new ByteArrayOutputStream();
  346. int c = 0;
  347. try {
  348. while((c = is.read()) != -1)
  349. buf.write(c);
  350. is.close();
  351. } catch(IOException e) {
  352. throw new Exception("Error reading from " + is);
  353. }
  354. return buf.toByteArray();
  355. }
  356. static boolean overwrite(File f) {
  357. if(overwrite || !f.exists())
  358. return true;
  359. YesNoCancelDialog d = new YesNoCancelDialog(
  360. IJ.getInstance() != null ? IJ.getInstance() : new Frame(),
  361. "Overwrite?",
  362. f.getAbsolutePath() + " exists already\n" +
  363. "Press OK to overwrite, or Cancel/No to skip");
  364. return d.yesPressed();
  365. }
  366. static void println(String s) {
  367. IJ.log(s);
  368. }
  369. static void print(String s) {
  370. IJ.log(s);
  371. }
  372. /**
  373. * Recursively delete a file or directory.
  374. */
  375. static void rm(File f) {
  376. if(!f.exists())
  377. return;
  378. if(f.isDirectory()) {
  379. File[] ch = f.listFiles();
  380. for(File child : ch)
  381. rm(child);
  382. }
  383. f.delete();
  384. }
  385. }