/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org> Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.lib.jogl; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import javax.swing.SwingUtilities; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.modules.InstalledFileLocator; import org.openide.modules.ModuleInstall; import org.openide.util.Exceptions; import org.openide.util.NbBundle; /** * Manages the JOGL natives loading. Thanks to Michael Bien, Lilian Chamontin and Kenneth Russell. * * @author Mathieu Bastan */ public class JOGLNativesInstaller extends ModuleInstall { private NativeLibInfo nativeLibInfo; //Compatible nativeLibInfo with OS/Arch private boolean exitOnFatalError = true; public void restored() { if (findCompatibleOsAndArch()) { String nativeArch = nativeLibInfo.getSubDirectoryPath(); File joglDistFolder = InstalledFileLocator.getDefault().locate("modules/lib/" + nativeArch, null, false); if (joglDistFolder != null) { loadNatives(joglDistFolder); } else { fatalError(String.format(NbBundle.getMessage(JOGLNativesInstaller.class, "JOGLNativesInstaller_error1"), new Object[]{nativeArch})); } } } //============================================================= //============================================================= private boolean findCompatibleOsAndArch() { String osName = System.getProperty("os.name"); String osArch = System.getProperty("os.arch"); if (checkOSAndArch(osName, osArch)) { return true; } else { fatalError(String.format(NbBundle.getMessage(JOGLNativesInstaller.class, "JOGLNativesInstaller_error2"), new Object[]{osName, osArch})); } return false; } boolean checkOSAndArch(String osName, String osArch) { for (int i = 0; i < allNativeLibInfo.length; i++) { NativeLibInfo info = allNativeLibInfo[i]; if (info.matchesOSAndArch(osName, osArch)) { nativeLibInfo = info; return true; } } return false; } private void loadNatives(final File nativeLibDir) { try { // back to the EDT SwingUtilities.invokeAndWait(new Runnable() { public void run() { System.out.println("Loading native libraries"); // disable JOGL and GlueGen runtime library loading from elsewhere com.sun.opengl.impl.NativeLibLoader.disableLoading(); com.sun.gluegen.runtime.NativeLibLoader.disableLoading(); // Open GlueGen runtime library optimistically. Note that // currently we do not need this on any platform except X11 // ones, because JOGL doesn't use the GlueGen NativeLibrary // class anywhere except the DRIHack class, but if for // example we add JOAL support then we will need this on // every platform. loadLibrary(nativeLibDir, "gluegen-rt"); Class driHackClass = null; if (nativeLibInfo.mayNeedDRIHack()) { // Run the DRI hack try { driHackClass = Class.forName("com.sun.opengl.impl.x11.DRIHack"); driHackClass.getMethod("begin", new Class[]{}).invoke(null, new Object[]{}); } catch (Exception e) { e.printStackTrace(); } } // Load core JOGL native library loadLibrary(nativeLibDir, "jogl"); if (nativeLibInfo.mayNeedDRIHack()) { // End DRI hack try { driHackClass.getMethod("end", new Class[]{}).invoke(null, new Object[]{}); } catch (Exception e) { e.printStackTrace(); } } if (!nativeLibInfo.isMacOS()) { // borrowed from NativeLibLoader // Must pre-load JAWT on all non-Mac platforms to // ensure references from jogl_awt shared object // will succeed since JAWT shared object isn't in // default library path try { System.loadLibrary("jawt"); } catch (UnsatisfiedLinkError ex) { // Accessibility technologies load JAWT themselves; safe to continue // as long as JAWT is loaded by any loader if (ex.getMessage().indexOf("already loaded") == -1) { fatalError(String.format(NbBundle.getMessage(JOGLNativesInstaller.class, "JOGLNativesInstaller_error3"), new Object[]{})); } } } // Load AWT-specific native code loadLibrary(nativeLibDir, "jogl_awt"); } }); } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } catch (InvocationTargetException ex) { Exceptions.printStackTrace(ex); } } private void loadLibrary(File installDir, String libName) { String nativeLibName = nativeLibInfo.getNativeLibName(libName); try { System.load(new File(installDir, nativeLibName).getPath()); } catch (UnsatisfiedLinkError ex) { // should be safe to continue as long as the native is loaded by any loader if (ex.getMessage().indexOf("already loaded") == -1) { fatalError(String.format(NbBundle.getMessage(JOGLNativesInstaller.class, "JOGLNativesInstaller_error4"), new Object[]{nativeLibName})); } } } private void fatalError(String error) { Exception ex = new Exception(error); NotifyDescriptor.Exception e = new NotifyDescriptor.Exception(ex); DialogDisplayer.getDefault().notify(e); if (exitOnFatalError) { System.exit(1); } } private static class NativeLibInfo { private String osName; private String osArch; private String osNameAndArchPair; private String nativePrefix; private String nativeSuffix; public NativeLibInfo(String osName, String osArch, String osNameAndArchPair, String nativePrefix, String nativeSuffix) { this.osName = osName; this.osArch = osArch; this.osNameAndArchPair = osNameAndArchPair; this.nativePrefix = nativePrefix; this.nativeSuffix = nativeSuffix; } public boolean matchesOSAndArch(String osName, String osArch) { if (osName.toLowerCase().startsWith(this.osName)) { if ((this.osArch == null) || (osArch.toLowerCase().equals(this.osArch))) { return true; } } return false; } public boolean matchesNativeLib(String fileName) { if (fileName.toLowerCase().endsWith(nativeSuffix)) { return true; } return false; } public String formatNativeJarName(String nativeJarPattern) { return MessageFormat.format(nativeJarPattern, new Object[]{osNameAndArchPair}); } public String getNativeLibName(String baseName) { return nativePrefix + baseName + nativeSuffix; } public boolean isMacOS() { return (osName.equals("mac")); } public boolean mayNeedDRIHack() { return (!isMacOS() && !osName.equals("win")); } public String getSubDirectoryPath() { return osNameAndArchPair; } } private static final NativeLibInfo[] allNativeLibInfo = { new NativeLibInfo("win", "x86", "windows-i586", "", ".dll"), new NativeLibInfo("win", "amd64", "windows-amd64", "", ".dll"), new NativeLibInfo("win", "x86_64", "windows-amd64", "", ".dll"), new NativeLibInfo("mac", "ppc", "macosx-ppc", "lib", ".jnilib"), new NativeLibInfo("mac", "i386", "macosx-universal", "lib", ".jnilib"), new NativeLibInfo("mac", "x86_64", "macosx-universal", "lib", ".jnilib"), new NativeLibInfo("linux", "i386", "linux-i586", "lib", ".so"), new NativeLibInfo("linux", "x86", "linux-i586", "lib", ".so"), new NativeLibInfo("linux", "amd64", "linux-amd64", "lib", ".so"), new NativeLibInfo("linux", "x86_64", "linux-amd64", "lib", ".so"), new NativeLibInfo("sunos", "sparc", "solaris-sparc", "lib", ".so"), new NativeLibInfo("sunos", "sparcv9", "solaris-sparcv9", "lib", ".so"), new NativeLibInfo("sunos", "x86", "solaris-i586", "lib", ".so"), new NativeLibInfo("sunos", "amd64", "solaris-amd64", "lib", ".so"), new NativeLibInfo("sunos", "x86_64", "solaris-amd64", "lib", ".so") }; }