/*
* Copyright 2010-2015 Institut Pasteur.
*
* This file is part of Icy.
*
* Icy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Icy 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Icy. If not, see <http://www.gnu.org/licenses/>.
*/
package icy.main;
import icy.action.ActionManager;
import icy.common.Version;
import icy.file.FileUtil;
import icy.file.Loader;
import icy.gui.dialog.ConfirmDialog;
import icy.gui.dialog.IdConfirmDialog;
import icy.gui.dialog.IdConfirmDialog.Confirmer;
import icy.gui.frame.ExitFrame;
import icy.gui.frame.IcyExternalFrame;
import icy.gui.frame.SplashScreenFrame;
import icy.gui.frame.progress.AnnounceFrame;
import icy.gui.frame.progress.ToolTipFrame;
import icy.gui.main.MainFrame;
import icy.gui.main.MainInterface;
import icy.gui.main.MainInterfaceBatch;
import icy.gui.main.MainInterfaceGui;
import icy.gui.system.NewVersionFrame;
import icy.gui.util.LookAndFeelUtil;
import icy.imagej.ImageJPatcher;
import icy.math.UnitUtil;
import icy.network.NetworkUtil;
import icy.plugin.PluginDescriptor;
import icy.plugin.PluginInstaller;
import icy.plugin.PluginLauncher;
import icy.plugin.PluginLoader;
import icy.plugin.PluginUpdater;
import icy.plugin.abstract_.Plugin;
import icy.preferences.ApplicationPreferences;
import icy.preferences.GeneralPreferences;
import icy.preferences.IcyPreferences;
import icy.preferences.PluginPreferences;
import icy.sequence.Sequence;
import icy.system.AppleUtil;
import icy.system.IcyExceptionHandler;
import icy.system.IcySecurityManager;
import icy.system.SingleInstanceCheck;
import icy.system.SystemUtil;
import icy.system.audit.Audit;
import icy.system.thread.ThreadUtil;
import icy.update.IcyUpdater;
import icy.util.StringUtil;
import icy.workspace.WorkspaceInstaller;
import icy.workspace.WorkspaceLoader;
import ij.ImageJ;
import java.awt.EventQueue;
import java.beans.PropertyVetoException;
import java.io.File;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;
import vtk.vtkNativeLibrary;
import vtk.vtkVersion;
/**
* <h3>Icy - copyright 2017 Institut Pasteur</h3> An open community platform for bio image analysis<br>
* <i>http://icy.bioimageanalysis.org</i><br>
* <br>
* Icy has been created by the Bio Image Analysis team at Institut Pasteur<br>
* <i>https://research.pasteur.fr/fr/team/bioimage-analysis</i><br>
* <br>
* Icy is free and open source, it has been funded both by Institut Pasteur and the FBI consortium<br>
* <i>https://france-bioimaging.org</i><br>
* <br>
* Source code is always provided in the main application package (in the icy.jar archive file) but can be also browsed
* from the GitHub repository<br>
* <i>https://github.com/Icy-imaging/Icy-Kernel</i><br>
* <br>
*
* @author Stephane Dallongeville
* @author Fabrice de Chaumont
*/
public class Icy
{
public static final String LIB_PATH = "lib";
public static final int EXIT_FORCE_DELAY = 3000;
/**
* Icy Version
*/
public static Version version = new Version("1.9.1.0");
/**
* Main interface
*/
private static MainInterface mainInterface = null;
/**
* Unique instance checker
*/
static FileLock lock = null;
/**
* private splash for initial loading
*/
static SplashScreenFrame splashScreen = null;
/**
* VTK library loaded flag
*/
static boolean vtkLibraryLoaded = false;
/**
* ITK library loaded flag
*/
static boolean itkLibraryLoaded = false;
/**
* No splash screen flag (default = false)
*/
static boolean noSplash = false;
/**
* Exiting flag
*/
static boolean exiting = false;
/**
* Startup parameters
*/
static String[] args;
static String[] pluginArgs;
static String startupPluginName;
static Plugin startupPlugin;
static String startupImage;
/**
* internals
*/
static ExitFrame exitFrame = null;
static Thread terminer = null;
/**
* @param args
* Received from the command line.
*/
public static void main(String[] args)
{
boolean headless = false;
try
{
System.out.println("Initializing...");
System.out.println();
// handle arguments (must be the first thing to do)
headless = handleAppArgs(args);
// force headless if we have a headless system
if (!headless && SystemUtil.isHeadLess())
headless = true;
// initialize preferences
IcyPreferences.init();
// check if Icy is already running
lock = SingleInstanceCheck.lock("icy");
if (lock == null)
{
// we always accept multi instance in headless mode
if (!headless)
{
// we need to use our custom ConfirmDialog as
// Icy.getMainInterface().isHeadless() will return false here
final Confirmer confirmer = new Confirmer("Confirmation",
"Icy is already running on this computer. Start anyway ?", JOptionPane.YES_NO_OPTION,
ApplicationPreferences.ID_SINGLE_INSTANCE);
ThreadUtil.invokeNow(confirmer);
if (!confirmer.getResult())
{
System.out.println("Exiting...");
// save preferences
IcyPreferences.save();
// and quit
System.exit(0);
return;
}
}
}
if (!headless && !noSplash)
{
// prepare splashScreen (ok to create it here as we are not yet in substance laf)
splashScreen = new SplashScreenFrame();
// It's important to initialize AWT now (with InvokeNow(...) for instance) to avoid
// the JVM deadlock bug (id: 5104239). It happen when the AWT thread is initialized
// while others threads load some new library with ClassLoader.loadLibrary
// display splash NOW (don't use ThreadUtil as headless is still false here)
EventQueue.invokeAndWait(new Runnable()
{
@Override
public void run()
{
// display splash screen
splashScreen.setVisible(true);
}
});
}
// set LOCI debug level (do it immediately as it can quickly show some log messages)
loci.common.DebugTools.enableLogging("ERROR");
// initialize network (need preferences)
NetworkUtil.init();
// load plugins classes (need preferences init)
PluginLoader.reloadAsynch();
WorkspaceLoader.reloadAsynch();
// patches ImageJ classes
ImageJPatcher.applyPatches();
// build main interface
if (headless)
mainInterface = new MainInterfaceBatch();
else
mainInterface = new MainInterfaceGui();
}
catch (Throwable t)
{
// any error at this point is fatal
fatalError(t, headless);
}
if (!headless)
{
// do it on AWT thread NOW as this is what we want first
ThreadUtil.invokeNow(new Runnable()
{
@Override
public void run()
{
try
{
// init Look And Feel (need mainInterface instance)
LookAndFeelUtil.init();
// init need "mainInterface" variable to be initialized
getMainInterface().init();
}
catch (Throwable t)
{
// any error here is fatal
fatalError(t, false);
}
}
});
}
else
{
// simple main interface init
getMainInterface().init();
}
// splash screen initialized --> hide it
if (splashScreen != null)
{
// then do less important stuff later
ThreadUtil.invokeLater(new Runnable()
{
@Override
public void run()
{
// we can now hide splash as we have interface
splashScreen.dispose();
splashScreen = null;
}
});
}
// show general informations
System.out.println(SystemUtil.getJavaName() + " " + SystemUtil.getJavaVersion() + " ("
+ SystemUtil.getJavaArchDataModel() + " bit)");
System.out.println("Running on " + SystemUtil.getOSName() + " " + SystemUtil.getOSVersion() + " ("
+ SystemUtil.getOSArch() + ")");
System.out.println("Number of processors : " + SystemUtil.getNumberOfCPUs());
System.out.println("System total memory : " + UnitUtil.getBytesString(SystemUtil.getTotalMemory()));
System.out.println("System available memory : " + UnitUtil.getBytesString(SystemUtil.getFreeMemory()));
System.out.println("Max java memory : " + UnitUtil.getBytesString(SystemUtil.getJavaMaxMemory()));
if (headless)
System.out.println("Headless mode.");
System.out.println();
// initialize OSX specific GUI stuff
if (!headless && SystemUtil.isMac())
AppleUtil.init();
// initialize security
IcySecurityManager.init();
// initialize exception handler
IcyExceptionHandler.init();
// initialize action manager
ActionManager.init();
// prepare native library files (need preferences init)
nativeLibrariesInit();
// changed version ?
if (!ApplicationPreferences.getVersion().equals(Icy.version))
{
// not headless ?
if (!headless)
{
// display the new version information
final String changeLog = Icy.getChangeLog();
// show the new version frame
if (!StringUtil.isEmpty(changeLog))
{
ThreadUtil.invokeNow(new Runnable()
{
@Override
public void run()
{
new NewVersionFrame(Icy.getChangeLog());
}
});
}
}
// force check update for the new version
GeneralPreferences.setLastUpdateCheckTime(0);
}
final long currentTime = System.currentTimeMillis();
final long halfDayInterval = 1000 * 60 * 60 * 12;
// check only once per 12 hours slice
if (currentTime > (GeneralPreferences.getLastUpdateCheckTime() + halfDayInterval))
{
// check for core update
if (GeneralPreferences.getAutomaticUpdate())
IcyUpdater.checkUpdate(true);
// check for plugin update
if (PluginPreferences.getAutomaticUpdate())
PluginUpdater.checkUpdate(true);
// update last update check time
GeneralPreferences.setLastUpdateCheckTime(currentTime);
}
// update version info
ApplicationPreferences.setVersion(Icy.version);
// set LOCI debug level
// loci.common.DebugTools.enableLogging("ERROR");
// set OGL debug level
// SystemUtil.setProperty("jogl.verbose", "TRUE");
// SystemUtil.setProperty("jogl.debug", "TRUE");
System.out.println();
System.out.println("Icy Version " + version + " started !");
System.out.println();
checkParameters();
// handle startup arguments
if (startupImage != null)
Icy.getMainInterface().addSequence(Loader.loadSequence(FileUtil.getGenericPath(startupImage), 0, false));
// wait while updates are occurring before starting command line plugin...
while (PluginUpdater.isCheckingForUpdate() || PluginInstaller.isProcessing()
|| WorkspaceInstaller.isProcessing())
ThreadUtil.sleep(1);
if (startupPluginName != null)
{
PluginLoader.waitWhileLoading();
final PluginDescriptor plugin = PluginLoader.getPlugin(startupPluginName);
if (plugin == null)
{
System.err.println("Could not launch plugin '" + startupPluginName + "': the plugin was not found.");
System.err.println("Be sure you correctly wrote the complete class name and respected the case.");
System.err.println("Ex: plugins.mydevid.analysis.MyPluginClass");
}
else
startupPlugin = PluginLauncher.start(plugin);
}
// headless mode ? we can exit now...
if (headless)
exit(false);
}
private static boolean handleAppArgs(String[] args)
{
final List<String> pluginArgsList = new ArrayList<String>();
startupImage = null;
startupPluginName = null;
startupPlugin = null;
boolean execute = false;
boolean headless = false;
// save the base arguments
Icy.args = args;
for (String arg : args)
{
// store plugin arguments
if (startupPluginName != null)
pluginArgsList.add(arg);
else if (execute)
startupPluginName = arg;
// special flag to disabled JCL (needed for development)
else if (arg.equalsIgnoreCase("--disableJCL") || arg.equalsIgnoreCase("-dJCL"))
PluginLoader.setJCLDisabled(true);
// headless mode
else if (arg.equalsIgnoreCase("--headless") || arg.equalsIgnoreCase("-hl"))
headless = true;
// disable splash-screen
else if (arg.equalsIgnoreCase("--nosplash") || arg.equalsIgnoreCase("-ns"))
noSplash = true;
// execute plugin
else if (arg.equalsIgnoreCase("--execute") || arg.equalsIgnoreCase("-x"))
execute = true;
// assume image name ?
else
startupImage = arg;
}
// save the plugin arguments
Icy.pluginArgs = pluginArgsList.toArray(new String[pluginArgsList.size()]);
return headless;
}
static void checkParameters()
{
// we are using a 32 bits JVM with a 64 bits OS --> warn the user
if (SystemUtil.isWindows64() && SystemUtil.is32bits())
{
final String text = "You're using a 32 bits Java with a 64 bits OS, try to upgrade to 64 bits java for better performance !";
System.out.println("Warning: " + text);
if (!Icy.getMainInterface().isHeadLess())
new ToolTipFrame("<html>" + text + "</html>", 15, "badJavaArchTip");
}
// we are using java 6 on OSX --> warn the user
final double javaVersion = SystemUtil.getJavaVersionAsNumber();
if ((javaVersion > 0) && (javaVersion < 1.7d) && SystemUtil.isMac())
{
final String text = "It looks like you're using a old version of Java (1.6)<br>"
+ "It's recommended to use last JDK 8 for OSX for a better user experience.<br>See the <a href=\"http://icy.bioimageanalysis.org/faq#35\">FAQ</a> to get information about how to update java.";
System.out.println("Warning: " + text);
if (!Icy.getMainInterface().isHeadLess())
new ToolTipFrame("<html>" + text + "</html>", 15, "outdatedJavaOSX");
}
// detect bad memory setting
if ((ApplicationPreferences.getMaxMemoryMB() <= 128) && (ApplicationPreferences.getMaxMemoryMBLimit() > 256))
{
final String text = "Your maximum memory setting is low, you should increase it in Preferences.";
System.out.println("Warning: " + text);
if (!Icy.getMainInterface().isHeadLess())
new ToolTipFrame("<html>" + text + "</html>", 15, "lowMemoryTip");
}
else if (ApplicationPreferences.getMaxMemoryMB() < (ApplicationPreferences.getDefaultMemoryMB() / 2))
{
if (!Icy.getMainInterface().isHeadLess())
{
new ToolTipFrame(
"<html><b>Tip:</b> you can increase your maximum memory in preferences setting.</html>", 15,
"maxMemoryTip");
}
}
if (!Icy.getMainInterface().isHeadLess())
{
// welcome tip !
final ToolTipFrame tooltip = new ToolTipFrame("<html>Access the main menu by clicking on top left icon<br>"
+ "<img src=\"" + Icy.class.getResource("/res/image/help/main_menu.png").toString()
+ "\" /></html>", 30, "mainMenuTip");
tooltip.setSize(456, 240);
}
}
static void fatalError(Throwable t, boolean headless)
{
// hide splashScreen if needed
if ((splashScreen != null) && (splashScreen.isVisible()))
splashScreen.dispose();
// show error in console
IcyExceptionHandler.showErrorMessage(t, true);
// and show error in dialog if not headless
if (!headless)
{
JOptionPane.showMessageDialog(null, IcyExceptionHandler.getErrorMessage(t, true), "Fatal error",
JOptionPane.ERROR_MESSAGE);
}
// exit with error code 1
System.exit(1);
}
/**
* Restart application with user confirmation
*/
public static void confirmRestart()
{
confirmRestart(null);
}
/**
* Restart application with user confirmation (custom message)
*/
public static void confirmRestart(String message)
{
final String mess;
if (StringUtil.isEmpty(message))
mess = "Application need to be restarted so changes can take effet. Do it now ?";
else
mess = message;
if (ConfirmDialog.confirm(mess))
// restart application now
exit(true);
}
/**
* Show announcement to restart application
*/
public static void announceRestart()
{
announceRestart(null);
}
/**
* Show announcement to restart application (custom message)
*/
public static void announceRestart(String message)
{
final String mess;
if (StringUtil.isEmpty(message))
mess = "Application need to be restarted so changes can take effet.";
else
mess = message;
if (Icy.getMainInterface().isHeadLess())
{
// just display this message
System.out.println(mess);
}
else
{
new AnnounceFrame(mess, "Restart Now", new Runnable()
{
@Override
public void run()
{
// restart application now
exit(true);
}
}, 20);
}
}
/**
* Returns <code>true</code> if application can exit.<br>
* Shows a confirmation dialog if setting requires it or if it's unsafe to exit now.
*/
public static boolean canExit(boolean showConfirm)
{
// we first check if externals listeners allow existing
if (!getMainInterface().canExitExternal())
return false;
// headless mode --> allow exit
if (Icy.getMainInterface().isHeadLess())
return true;
// PluginInstaller or WorkspaceInstaller not running
final boolean safeExit = (!PluginInstaller.isProcessing()) && (!WorkspaceInstaller.isProcessing());
// not safe, need confirmation
if (!safeExit)
{
if (!ConfirmDialog.confirm("Quit the application",
"Some processes are not yet completed, are you sure you want to quit ?",
ConfirmDialog.YES_NO_CANCEL_OPTION))
return false;
return true;
}
else if (showConfirm && GeneralPreferences.getExitConfirm())
{
// we need user confirmation
if (!IdConfirmDialog.confirm("Quit the application ?", GeneralPreferences.ID_CONFIRM_EXIT))
return false;
return true;
}
return true;
}
/**
* Exit Icy, returns <code>true</code> if the operation should success.<br>
* Note that the method is asynchronous so you still have a bit of time to execute some stuff before the application
* actually exit.
*/
public static boolean exit(final boolean restart)
{
// check we can exit application
if (!canExit(!restart))
return false;
// already existing
if (exiting && terminer.isAlive())
{
// set focus on exit frame
if (exitFrame != null)
exitFrame.requestFocus();
// return true;
return true;
}
// we don't want to be in EDT here and avoid BG runner
// as we test for BG runner completion
terminer = new Thread(new Runnable()
{
@Override
public void run()
{
// mark the application as exiting
exiting = true;
System.out.println("Exiting...");
final ImageJ ij = Icy.getMainInterface().getImageJ();
// clean ImageJ exit
if (ij != null)
ij.quit();
// get main frame
final MainFrame mainFrame = Icy.getMainInterface().getMainFrame();
// disconnect from chat (not needed but preferred)
if (mainFrame != null)
mainFrame.getChat().disconnect("Icy closed");
// close all icyFrames (force wait completion)
ThreadUtil.invokeNow(new Runnable()
{
@Override
public void run()
{
// for (IcyFrame frame : IcyFrame.getAllFrames())
// frame.close();
// close all JInternalFrames
final JDesktopPane desktopPane = Icy.getMainInterface().getDesktopPane();
if (desktopPane != null)
{
for (JInternalFrame frame : desktopPane.getAllFrames())
{
// if (frame instanceof IcyInternalFrame)
// {
// final IcyInternalFrame iFrame = (IcyInternalFrame) frame;
// if (!iFrame.isClosed())
// iFrame.close(true);
// if (iFrame.getDefaultCloseOperation() !=
// WindowConstants.DISPOSE_ON_CLOSE)
// iFrame.dispose();
// }
// else
// {
try
{
frame.setClosed(true);
}
catch (PropertyVetoException e)
{
// if (frame.getDefaultCloseOperation() !=
// WindowConstants.DISPOSE_ON_CLOSE)
frame.dispose();
}
// }
}
}
// then close all external frames except main frame
for (JFrame frame : Icy.getMainInterface().getExternalFrames())
{
if (frame != mainFrame)
{
if (frame instanceof IcyExternalFrame)
{
final IcyExternalFrame iFrame = (IcyExternalFrame) frame;
iFrame.close();
if (iFrame.getDefaultCloseOperation() != WindowConstants.DISPOSE_ON_CLOSE)
iFrame.dispose();
}
else
frame.dispose();
}
}
}
});
// stop daemon plugin
PluginLoader.stopDaemons();
// shutdown background processor after frame close
ThreadUtil.shutdown();
// headless mode
if (Icy.getMainInterface().isHeadLess())
{
// final long start = System.currentTimeMillis();
// // wait 10s max for background processors completed theirs tasks
// while (!ThreadUtil.isShutdownAndTerminated() && ((System.currentTimeMillis()
// - start) < 10 * 1000))
// ThreadUtil.sleep(1);
// wait that background processors completed theirs tasks
while (!ThreadUtil.isShutdownAndTerminated())
ThreadUtil.sleep(1);
}
else
{
// need to create the exit frame in EDT
ThreadUtil.invokeNow(new Runnable()
{
@Override
public void run()
{
// create and display the exit frame
exitFrame = new ExitFrame(EXIT_FORCE_DELAY);
}
});
// wait that background processors completed theirs tasks
while (!ThreadUtil.isShutdownAndTerminated() && !exitFrame.isForced())
ThreadUtil.sleep(1);
// need to dispose the exit frame in EDT (else we can have deadlock)
ThreadUtil.invokeNow(new Runnable()
{
@Override
public void run()
{
// can close the exit frame now
exitFrame.dispose();
}
});
}
// need to dispose the main frame in EDT (else we can have deadlock)
ThreadUtil.invokeNow(new Runnable()
{
@Override
public void run()
{
// finally close the main frame
if (mainFrame != null)
mainFrame.dispose();
}
});
// save preferences
IcyPreferences.save();
// save audit data
Audit.save();
// clean up native library files
// unPrepareNativeLibraries();
if (lock != null)
SingleInstanceCheck.release(lock);
final boolean doUpdate = IcyUpdater.getWantUpdate();
// launch updater if needed
if (doUpdate || restart)
IcyUpdater.launchUpdater(doUpdate, restart);
// good exit
System.exit(0);
}
});
terminer.setName("Icy Shutdown");
terminer.start();
return true;
}
/**
* @param force
* @deprecated use <code>exit(boolean)</code> instead
*/
@Deprecated
public static boolean exit(final boolean restart, boolean force)
{
return exit(restart);
}
/**
* Return true is VTK library loaded.
*/
public static boolean isVtkLibraryLoaded()
{
return vtkLibraryLoaded;
}
/**
* Return true is VTK library loaded.
*/
public static boolean isItkLibraryLoaded()
{
return itkLibraryLoaded;
}
/**
* @deprecated Use {@link MainInterface#isHeadLess()} instead.
*/
@Deprecated
public static boolean isHeadLess()
{
return getMainInterface().isHeadLess();
}
/**
* Return true is the application is currently exiting.
*/
public static boolean isExiting()
{
return exiting;
}
/**
* Return the main Icy interface.
*/
public static MainInterface getMainInterface()
{
// batch mode
if (mainInterface == null)
mainInterface = new MainInterfaceBatch();
return mainInterface;
}
/**
* Returns the command line arguments
*/
public static String[] getCommandLineArgs()
{
return args;
}
/**
* Returns the plugin command line arguments
*/
public static String[] getCommandLinePluginArgs()
{
return pluginArgs;
}
/**
* Clear the plugin command line arguments.<br>
* This method should be called after the launching plugin actually 'consumed' the startup
* arguments.
*/
public static void clearCommandLinePluginArgs()
{
pluginArgs = new String[0];
}
/**
* Returns the startup plugin if any
*/
public static Plugin getStartupPlugin()
{
return startupPlugin;
}
/**
* Return content of the <code>CHANGELOG.txt</code> file
*/
public static String getChangeLog()
{
if (FileUtil.exists("CHANGELOG.txt"))
return new String(FileUtil.load("CHANGELOG.txt", false));
return "";
}
/**
* Return content of the <code>COPYING.txt</code> file
*/
public static String getLicense()
{
if (FileUtil.exists("COPYING.txt"))
return new String(FileUtil.load("COPYING.txt", false));
return "";
}
/**
* Return content of the <code>README.txt</code> file
*/
public static String getReadMe()
{
if (FileUtil.exists("README.txt"))
return new String(FileUtil.load("README.txt", false));
return "";
}
/**
* @deprecated Uses <code>Icy.getMainInterface().addSequence(Sequence)</code> instead.
*/
@Deprecated
public static void addSequence(final Sequence sequence)
{
Icy.getMainInterface().addSequence(sequence);
}
static void nativeLibrariesInit()
{
// build the local native library path
final String libPath = LIB_PATH + FileUtil.separator + SystemUtil.getOSArchIdString();
final File libFile = new File(libPath);
// get all files in local native library path
final File[] files = FileUtil.getFiles(libFile, null, true, true, false);
final ArrayList<String> directories = new ArrayList<String>();
// add base local native library path to user library paths
directories.add(libFile.getAbsolutePath());
// add base temporary native library path to user library paths
directories.add(SystemUtil.getTempLibraryDirectory());
for (File f : files)
{
if (f.isDirectory())
{
// add all directories to user library paths
final String filePath = f.getAbsolutePath();
if (!directories.contains(filePath))
directories.add(filePath);
}
}
// add lib folder for unix system
if (SystemUtil.isUnix())
{
directories.add("/lib");
directories.add("/usr/lib");
if (SystemUtil.is64bits())
{
directories.add("/lib64");
directories.add("/lib/x86_64");
directories.add("/lib/x86_64-linux-gnu");
directories.add("/usr/lib64");
directories.add("/usr/lib/x86_64");
directories.add("/usr/lib/x86_64-linux-gnu");
}
else
{
directories.add("/lib/x86");
directories.add("/lib/x86-linux-gnu");
directories.add("/usr/lib/x86");
directories.add("/usr/lib/x86-linux-gnu");
}
}
if (!SystemUtil.addToJavaLibraryPath(directories.toArray(new String[directories.size()])))
System.err.println("Native libraries may not load correctly.");
// load native libraries
loadVtkLibrary(libPath);
// loadItkLibrary(libPath);
// disable native lib support for JAI as we don't provide them (for the moment)
SystemUtil.setProperty("com.sun.media.jai.disableMediaLib", "true");
}
private static void loadVtkLibrary(String libPath)
{
final String vtkLibPath = libPath + FileUtil.separator + "vtk";
// we load it directly from inner lib path if possible
System.setProperty("vtk.lib.dir", vtkLibPath);
vtkLibraryLoaded = false;
try
{
// if (SystemUtil.isUnix())
// {
// vtkNativeLibrary.LoadAllNativeLibraries();
//
// // assume VTK loaded if at least 1 native library is loaded
// for (vtkNativeLibrary lib : vtkNativeLibrary.values())
// if (lib.IsLoaded())
// vtkLibraryLoaded = true;
// }
// else
{
loadLibrary(vtkLibPath, "vtkalglib");
loadLibrary(vtkLibPath, "vtkexpat");
loadLibrary(vtkLibPath, "vtkDICOMParser");
loadLibrary(vtkLibPath, "vtkjpeg");
loadLibrary(vtkLibPath, "vtkjsoncpp");
loadLibrary(vtkLibPath, "vtkzlib");
loadLibrary(vtkLibPath, "vtkoggtheora", false);
loadLibrary(vtkLibPath, "vtkverdict");
loadLibrary(vtkLibPath, "vtkpng");
loadLibrary(vtkLibPath, "vtkgl2ps", false); //
loadLibrary(vtkLibPath, "vtktiff");
loadLibrary(vtkLibPath, "vtklibxml2");
loadLibrary(vtkLibPath, "vtkproj4");
loadLibrary(vtkLibPath, "vtksys");
loadLibrary(vtkLibPath, "vtkfreetype");
loadLibrary(vtkLibPath, "vtkmetaio");
loadLibrary(vtkLibPath, "vtkftgl", false);
loadLibrary(vtkLibPath, "vtkftgl2", false); //
loadLibrary(vtkLibPath, "vtkglew", false);
loadLibrary(vtkLibPath, "vtkCommonCore");
loadLibrary(vtkLibPath, "vtkWrappingJava");
loadLibrary(vtkLibPath, "vtkCommonSystem");
loadLibrary(vtkLibPath, "vtkCommonMath");
loadLibrary(vtkLibPath, "vtkCommonMisc");
loadLibrary(vtkLibPath, "vtkCommonTransforms");
if (SystemUtil.isMac())
{
loadLibrary(vtkLibPath, "vtkhdf5.8.0.2", false);
loadLibrary(vtkLibPath, "vtkhdf5_hl.8.0.2", false);
}
else
{
loadLibrary(vtkLibPath, "vtkhdf5", false);
loadLibrary(vtkLibPath, "vtkhdf5_hl", false);
}
loadLibrary(vtkLibPath, "vtkNetCDF");
loadLibrary(vtkLibPath, "vtkNetCDF_cxx");
loadLibrary(vtkLibPath, "vtkCommonDataModel");
loadLibrary(vtkLibPath, "vtkCommonColor");
loadLibrary(vtkLibPath, "vtkCommonComputationalGeometry");
loadLibrary(vtkLibPath, "vtkCommonExecutionModel");
loadLibrary(vtkLibPath, "vtkexoIIc");
loadLibrary(vtkLibPath, "vtkFiltersVerdict");
loadLibrary(vtkLibPath, "vtkFiltersProgrammable");
loadLibrary(vtkLibPath, "vtkImagingMath");
loadLibrary(vtkLibPath, "vtkIOCore");
loadLibrary(vtkLibPath, "vtkIOEnSight");
loadLibrary(vtkLibPath, "vtkIOVideo");
loadLibrary(vtkLibPath, "vtkIOLegacy");
loadLibrary(vtkLibPath, "vtkIONetCDF");
loadLibrary(vtkLibPath, "vtkIOXMLParser");
loadLibrary(vtkLibPath, "vtkIOXML");
loadLibrary(vtkLibPath, "vtkIOImage");
loadLibrary(vtkLibPath, "vtksqlite", false);
loadLibrary(vtkLibPath, "vtkIOSQL");
loadLibrary(vtkLibPath, "vtkIOMovie");
loadLibrary(vtkLibPath, "vtkParallelCore");
loadLibrary(vtkLibPath, "vtkImagingCore");
loadLibrary(vtkLibPath, "vtkFiltersCore");
loadLibrary(vtkLibPath, "vtkImagingColor");
loadLibrary(vtkLibPath, "vtkImagingFourier");
loadLibrary(vtkLibPath, "vtkImagingSources");
loadLibrary(vtkLibPath, "vtkImagingHybrid");
loadLibrary(vtkLibPath, "vtkImagingStatistics");
loadLibrary(vtkLibPath, "vtkIOGeometry");
loadLibrary(vtkLibPath, "vtkIOPLY");
loadLibrary(vtkLibPath, "vtkFiltersSelection");
loadLibrary(vtkLibPath, "vtkImagingGeneral");
loadLibrary(vtkLibPath, "vtkImagingStencil");
loadLibrary(vtkLibPath, "vtkImagingMorphological");
loadLibrary(vtkLibPath, "vtkFiltersGeometry");
loadLibrary(vtkLibPath, "vtkFiltersStatistics");
loadLibrary(vtkLibPath, "vtkFiltersImaging");
loadLibrary(vtkLibPath, "vtkIOLSDyna");
loadLibrary(vtkLibPath, "vtkFiltersGeneral");
loadLibrary(vtkLibPath, "vtkFiltersHyperTree");
loadLibrary(vtkLibPath, "vtkFiltersSMP");
loadLibrary(vtkLibPath, "vtkFiltersTexture");
loadLibrary(vtkLibPath, "vtkFiltersAMR");
loadLibrary(vtkLibPath, "vtkFiltersExtraction");
loadLibrary(vtkLibPath, "vtkFiltersSources");
loadLibrary(vtkLibPath, "vtkIOExodus");
loadLibrary(vtkLibPath, "vtkFiltersGeneric");
loadLibrary(vtkLibPath, "vtkFiltersModeling");
loadLibrary(vtkLibPath, "vtkIOAMR");
loadLibrary(vtkLibPath, "vtkFiltersFlowPaths");
loadLibrary(vtkLibPath, "vtkInfovisCore");
loadLibrary(vtkLibPath, "vtkIOInfovis");
loadLibrary(vtkLibPath, "vtkInfovisLayout");
loadLibrary(vtkLibPath, "vtkRenderingCore");
loadLibrary(vtkLibPath, "vtkRenderingLOD");
loadLibrary(vtkLibPath, "vtkRenderingImage");
loadLibrary(vtkLibPath, "vtkRenderingFreeType");
loadLibrary(vtkLibPath, "vtkDomainsChemistry");
loadLibrary(vtkLibPath, "vtkDomainsChemistryOpenGL2", false);
loadLibrary(vtkLibPath, "vtkInteractionStyle");
loadLibrary(vtkLibPath, "vtkIOImport");
loadLibrary(vtkLibPath, "vtkRenderingAnnotation");
loadLibrary(vtkLibPath, "vtkRenderingLabel");
loadLibrary(vtkLibPath, "vtkFiltersHybrid");
loadLibrary(vtkLibPath, "vtkFiltersParallel");
loadLibrary(vtkLibPath, "vtkFiltersParallelImaging");
loadLibrary(vtkLibPath, "vtkIOMINC");
loadLibrary(vtkLibPath, "vtkIOParallel");
loadLibrary(vtkLibPath, "vtkRenderingVolume");
loadLibrary(vtkLibPath, "vtkRenderingVolumeAMR", false);
loadLibrary(vtkLibPath, "vtkInteractionWidgets");
loadLibrary(vtkLibPath, "vtkInteractionImage");
loadLibrary(vtkLibPath, "vtkViewsCore");
loadLibrary(vtkLibPath, "vtkRenderingOpenGL", false); //
loadLibrary(vtkLibPath, "vtkRenderingOpenGL2", false);
loadLibrary(vtkLibPath, "vtkRenderingLIC", false); //
loadLibrary(vtkLibPath, "vtkRenderingVolumeOpenGL", false); //
loadLibrary(vtkLibPath, "vtkRenderingVolumeOpenGL2", false);
loadLibrary(vtkLibPath, "vtkRenderingContext2D");
loadLibrary(vtkLibPath, "vtkRenderingContextOpenGL", false); //
loadLibrary(vtkLibPath, "vtkRenderingContextOpenGL2", false);
loadLibrary(vtkLibPath, "vtkRenderingGL2PS", false); //
loadLibrary(vtkLibPath, "vtkViewsContext2D");
loadLibrary(vtkLibPath, "vtkGeovisCore");
loadLibrary(vtkLibPath, "vtkIOExport");
loadLibrary(vtkLibPath, "vtkChartsCore");
loadLibrary(vtkLibPath, "vtkViewsInfovis");
loadLibrary(vtkLibPath, "vtkViewsGeovis", false);
// JAVA wrapper
loadLibrary(vtkLibPath, "vtkCommonCoreJava");
loadLibrary(vtkLibPath, "vtkCommonSystemJava");
loadLibrary(vtkLibPath, "vtkCommonMathJava");
loadLibrary(vtkLibPath, "vtkCommonMiscJava");
loadLibrary(vtkLibPath, "vtkCommonTransformsJava");
loadLibrary(vtkLibPath, "vtkCommonDataModelJava");
loadLibrary(vtkLibPath, "vtkCommonColorJava");
loadLibrary(vtkLibPath, "vtkCommonComputationalGeometryJava");
loadLibrary(vtkLibPath, "vtkCommonExecutionModelJava");
loadLibrary(vtkLibPath, "vtkFiltersVerdictJava");
loadLibrary(vtkLibPath, "vtkFiltersProgrammableJava");
loadLibrary(vtkLibPath, "vtkImagingMathJava");
loadLibrary(vtkLibPath, "vtkIOCoreJava");
loadLibrary(vtkLibPath, "vtkIOEnSightJava");
loadLibrary(vtkLibPath, "vtkIOVideoJava");
loadLibrary(vtkLibPath, "vtkIOLegacyJava");
loadLibrary(vtkLibPath, "vtkIONetCDFJava");
loadLibrary(vtkLibPath, "vtkIOXMLParserJava");
loadLibrary(vtkLibPath, "vtkIOXMLJava");
loadLibrary(vtkLibPath, "vtkIOImageJava");
loadLibrary(vtkLibPath, "vtkIOSQLJava");
loadLibrary(vtkLibPath, "vtkIOMovieJava");
loadLibrary(vtkLibPath, "vtkParallelCoreJava");
loadLibrary(vtkLibPath, "vtkImagingCoreJava");
loadLibrary(vtkLibPath, "vtkFiltersCoreJava");
loadLibrary(vtkLibPath, "vtkImagingColorJava");
loadLibrary(vtkLibPath, "vtkImagingFourierJava");
loadLibrary(vtkLibPath, "vtkImagingSourcesJava");
loadLibrary(vtkLibPath, "vtkImagingHybridJava");
loadLibrary(vtkLibPath, "vtkImagingStatisticsJava");
loadLibrary(vtkLibPath, "vtkIOGeometryJava");
loadLibrary(vtkLibPath, "vtkIOPLYJava");
loadLibrary(vtkLibPath, "vtkFiltersSelectionJava");
loadLibrary(vtkLibPath, "vtkImagingGeneralJava");
loadLibrary(vtkLibPath, "vtkImagingStencilJava");
loadLibrary(vtkLibPath, "vtkImagingMorphologicalJava");
loadLibrary(vtkLibPath, "vtkFiltersGeometryJava");
loadLibrary(vtkLibPath, "vtkFiltersStatisticsJava");
loadLibrary(vtkLibPath, "vtkFiltersImagingJava");
loadLibrary(vtkLibPath, "vtkIOLSDynaJava");
loadLibrary(vtkLibPath, "vtkFiltersGeneralJava");
loadLibrary(vtkLibPath, "vtkFiltersHyperTreeJava");
loadLibrary(vtkLibPath, "vtkFiltersSMPJava");
loadLibrary(vtkLibPath, "vtkFiltersTextureJava");
loadLibrary(vtkLibPath, "vtkFiltersAMRJava");
loadLibrary(vtkLibPath, "vtkFiltersExtractionJava");
loadLibrary(vtkLibPath, "vtkFiltersSourcesJava");
loadLibrary(vtkLibPath, "vtkIOExodusJava");
loadLibrary(vtkLibPath, "vtkFiltersGenericJava");
loadLibrary(vtkLibPath, "vtkFiltersModelingJava");
loadLibrary(vtkLibPath, "vtkIOAMRJava");
loadLibrary(vtkLibPath, "vtkFiltersFlowPathsJava");
loadLibrary(vtkLibPath, "vtkInfovisCoreJava");
loadLibrary(vtkLibPath, "vtkIOInfovisJava");
loadLibrary(vtkLibPath, "vtkInfovisLayoutJava");
loadLibrary(vtkLibPath, "vtkRenderingCoreJava");
loadLibrary(vtkLibPath, "vtkRenderingLODJava");
loadLibrary(vtkLibPath, "vtkRenderingImageJava");
loadLibrary(vtkLibPath, "vtkRenderingFreeTypeJava");
loadLibrary(vtkLibPath, "vtkDomainsChemistryJava");
loadLibrary(vtkLibPath, "vtkDomainsChemistryOpenGL2Java", false);
loadLibrary(vtkLibPath, "vtkInteractionStyleJava");
loadLibrary(vtkLibPath, "vtkIOImportJava");
loadLibrary(vtkLibPath, "vtkRenderingAnnotationJava");
loadLibrary(vtkLibPath, "vtkRenderingLabelJava");
loadLibrary(vtkLibPath, "vtkFiltersHybridJava");
loadLibrary(vtkLibPath, "vtkFiltersParallelJava");
loadLibrary(vtkLibPath, "vtkFiltersParallelImagingJava");
loadLibrary(vtkLibPath, "vtkIOMINCJava");
loadLibrary(vtkLibPath, "vtkIOParallelJava");
loadLibrary(vtkLibPath, "vtkRenderingVolumeJava");
loadLibrary(vtkLibPath, "vtkRenderingVolumeAMRJava", false);
loadLibrary(vtkLibPath, "vtkInteractionWidgetsJava");
loadLibrary(vtkLibPath, "vtkInteractionImageJava");
loadLibrary(vtkLibPath, "vtkViewsCoreJava");
loadLibrary(vtkLibPath, "vtkRenderingOpenGLJava", false); //
loadLibrary(vtkLibPath, "vtkRenderingOpenGL2Java", false);
loadLibrary(vtkLibPath, "vtkRenderingLICJava", false); //
loadLibrary(vtkLibPath, "vtkRenderingVolumeOpenGLJava", false); //
loadLibrary(vtkLibPath, "vtkRenderingVolumeOpenGL2Java", false);
loadLibrary(vtkLibPath, "vtkRenderingContext2DJava");
loadLibrary(vtkLibPath, "vtkRenderingContextOpenGLJava", false); //
loadLibrary(vtkLibPath, "vtkRenderingContextOpenGL2Java", false);
loadLibrary(vtkLibPath, "vtkRenderingGL2PSJava", false); //
loadLibrary(vtkLibPath, "vtkViewsContext2DJava");
loadLibrary(vtkLibPath, "vtkGeovisCoreJava");
loadLibrary(vtkLibPath, "vtkIOExportJava");
loadLibrary(vtkLibPath, "vtkChartsCoreJava");
loadLibrary(vtkLibPath, "vtkViewsInfovisJava");
loadLibrary(vtkLibPath, "vtkViewsGeovisJava", false);
// VTK library successfully loaded
vtkLibraryLoaded = true;
}
// redirect vtk error log to file
vtkNativeLibrary.DisableOutputWindow(new File("vtk.log"));
}
catch (Throwable e)
{
IcyExceptionHandler.showErrorMessage(e, false, false);
}
if (vtkLibraryLoaded)
{
final String vv = new vtkVersion().GetVTKVersion();
System.out.println("VTK " + vv + " library successfully loaded...");
// final vtkJavaGarbageCollector vtkJavaGarbageCollector =
// vtkObjectBase.JAVA_OBJECT_MANAGER
// .getAutoGarbageCollector();
//
// set auto garbage collection for VTK (every 20 seconds should be enough)
// probably not a good idea...
// vtkJavaGarbageCollector.SetScheduleTime(5, TimeUnit.SECONDS);
// vtkJavaGarbageCollector.SetAutoGarbageCollection(true);
}
else
{
System.out.println("Cannot load VTK library...");
if (SystemUtil.isMac())
{
final String osVer = SystemUtil.getOSVersion();
if (osVer.startsWith("10.6") || osVer.startsWith("10.5"))
System.out.println("VTK 6.3 is not supported on OSX " + osVer
+ ", version 10.7 or above is required.");
}
}
}
private static void loadItkLibrary(String osDir)
{
final String itkLibDir = osDir + FileUtil.separator + "itk";
try
{
loadLibrary(itkLibDir, "SimpleITKJava", true);
System.out.println("SimpleITK library successfully loaded...");
itkLibraryLoaded = true;
}
catch (Throwable e)
{
System.out.println("Cannot load SimpleITK library...");
}
}
private static void loadLibrary(String dir, String name, boolean mandatory, boolean showLog)
{
if (mandatory)
SystemUtil.loadLibrary(dir, name);
else
{
try
{
SystemUtil.loadLibrary(dir, name);
}
catch (Throwable e)
{
if (showLog)
System.out.println("cannot load " + name + ", skipping...");
}
}
}
private static void loadLibrary(String dir, String name, boolean mandatory)
{
loadLibrary(dir, name, mandatory, false);
}
private static void loadLibrary(String dir, String name)
{
loadLibrary(dir, name, true, false);
}
static void nativeLibrariesShutdown()
{
// build the native local library path
final String path = LIB_PATH + FileUtil.separator + SystemUtil.getOSArchIdString();
// get file list (we don't want hidden files if any)
File[] libraryFiles = FileUtil.getFiles(new File(path), null, true, false, false);
// remove previous copied files
for (File libraryFile : libraryFiles)
{
// get file in root directory
final File file = new File(libraryFile.getName());
// invoke delete on exit if the file exists
if (file.exists())
file.deleteOnExit();
}
// get file list from temporary native library path
libraryFiles = FileUtil.getFiles(new File(SystemUtil.getTempLibraryDirectory()), null, true, false, false);
// remove previous copied files
for (File libraryFile : libraryFiles)
{
// delete file
if (!FileUtil.delete(libraryFile, false))
libraryFile.deleteOnExit();
}
}
}