001/*
002 * Copyright 2010-2019 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.main;
020
021import java.awt.EventQueue;
022import java.beans.PropertyVetoException;
023import java.io.File;
024import java.nio.channels.FileLock;
025import java.util.ArrayList;
026import java.util.List;
027
028import javax.swing.JDesktopPane;
029import javax.swing.JFrame;
030import javax.swing.JInternalFrame;
031import javax.swing.JOptionPane;
032import javax.swing.WindowConstants;
033
034import icy.action.ActionManager;
035import icy.common.Version;
036import icy.file.FileUtil;
037import icy.file.Loader;
038import icy.gui.dialog.ConfirmDialog;
039import icy.gui.dialog.IdConfirmDialog;
040import icy.gui.dialog.IdConfirmDialog.Confirmer;
041import icy.gui.frame.ExitFrame;
042import icy.gui.frame.IcyExternalFrame;
043import icy.gui.frame.SplashScreenFrame;
044import icy.gui.frame.progress.AnnounceFrame;
045import icy.gui.frame.progress.ToolTipFrame;
046import icy.gui.inspector.InspectorPanel;
047import icy.gui.main.MainFrame;
048import icy.gui.main.MainInterface;
049import icy.gui.main.MainInterfaceBatch;
050import icy.gui.main.MainInterfaceGui;
051import icy.gui.system.NewVersionFrame;
052import icy.gui.util.LookAndFeelUtil;
053import icy.image.cache.ImageCache;
054import icy.imagej.ImageJPatcher;
055import icy.math.UnitUtil;
056import icy.network.NetworkUtil;
057import icy.plugin.PluginDescriptor;
058import icy.plugin.PluginInstaller;
059import icy.plugin.PluginLauncher;
060import icy.plugin.PluginLoader;
061import icy.plugin.PluginUpdater;
062import icy.plugin.abstract_.Plugin;
063import icy.preferences.ApplicationPreferences;
064import icy.preferences.GeneralPreferences;
065import icy.preferences.IcyPreferences;
066import icy.preferences.PluginPreferences;
067import icy.sequence.Sequence;
068import icy.system.AppleUtil;
069import icy.system.IcyExceptionHandler;
070import icy.system.IcySecurityManager;
071import icy.system.SingleInstanceCheck;
072import icy.system.SystemUtil;
073import icy.system.audit.Audit;
074import icy.system.thread.ThreadUtil;
075import icy.update.IcyUpdater;
076import icy.util.StringUtil;
077import icy.workspace.WorkspaceInstaller;
078import icy.workspace.WorkspaceLoader;
079import ij.ImageJ;
080import vtk.vtkNativeLibrary;
081import vtk.vtkVersion;
082
083/**
084 * <h3>Icy - copyright 2019 Institut Pasteur</h3> An open community platform for bio image analysis<br>
085 * <i>http://icy.bioimageanalysis.org</i><br>
086 * <br>
087 * Icy has been created by the Bio Image Analysis team at Institut Pasteur<br>
088 * <i>https://research.pasteur.fr/fr/team/bioimage-analysis</i><br>
089 * <br>
090 * Icy is free and open source, it has been funded both by Institut Pasteur and the FBI consortium<br>
091 * <i>https://france-bioimaging.org</i><br>
092 * <br>
093 * Source code is always provided in the main application package (in the icy.jar archive file) but can be also browsed
094 * from the GitHub repository<br>
095 * <i>https://github.com/Icy-imaging/Icy-Kernel</i><br>
096 * <br>
097 *
098 * @author Stephane Dallongeville
099 * @author Fabrice de Chaumont
100 */
101public class Icy
102{
103    public static final String LIB_PATH = "lib";
104    public static final int EXIT_FORCE_DELAY = 3000;
105
106    /**
107     * Icy Version
108     */
109    public static Version version = new Version("2.0.1.0");
110
111    /**
112     * Main interface
113     */
114    private static MainInterface mainInterface = null;
115
116    /**
117     * Unique instance checker
118     */
119    static FileLock lock = null;
120
121    /**
122     * private splash for initial loading
123     */
124    static SplashScreenFrame splashScreen = null;
125
126    /**
127     * VTK library loaded flag
128     */
129    static boolean vtkLibraryLoaded = false;
130
131    /**
132     * ITK library loaded flag
133     */
134    static boolean itkLibraryLoaded = false;
135
136    /**
137     * No splash screen flag (default = false)
138     */
139    static boolean noSplash = false;
140    /**
141     * Exiting flag
142     */
143    static boolean exiting = false;
144
145    /**
146     * Startup parameters
147     */
148    static String[] args;
149    static String[] pluginArgs;
150    static String startupPluginName;
151    static Plugin startupPlugin;
152    static String startupImage;
153
154    /**
155     * internals
156     */
157    static ExitFrame exitFrame = null;
158    static Thread terminer = null;
159
160    /**
161     * @param args
162     *        Received from the command line.
163     */
164    public static void main(String[] args)
165    {
166        boolean headless = false;
167
168        try
169        {
170            System.out.println("Initializing...");
171            System.out.println();
172
173            // handle arguments (must be the first thing to do)
174            headless = handleAppArgs(args);
175
176            // force headless if we have a headless system
177            if (!headless && SystemUtil.isHeadLess())
178                headless = true;
179
180            // initialize preferences
181            IcyPreferences.init();
182
183            // check if Icy is already running
184            lock = SingleInstanceCheck.lock("icy");
185            if (lock == null)
186            {
187                // we always accept multi instance in headless mode
188                if (!headless)
189                {
190                    // we need to use our custom ConfirmDialog as
191                    // Icy.getMainInterface().isHeadless() will return false here
192                    final Confirmer confirmer = new Confirmer("Confirmation",
193                            "Icy is already running on this computer. Start anyway ?", JOptionPane.YES_NO_OPTION,
194                            ApplicationPreferences.ID_SINGLE_INSTANCE);
195
196                    ThreadUtil.invokeNow(confirmer);
197
198                    if (!confirmer.getResult())
199                    {
200                        System.out.println("Exiting...");
201                        // save preferences
202                        IcyPreferences.save();
203                        // and quit
204                        System.exit(0);
205                        return;
206                    }
207                }
208            }
209
210            // fix possible IllegalArgumentException on Swing sorting
211            System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
212
213            if (!headless && !noSplash)
214            {
215                // prepare splashScreen (ok to create it here as we are not yet in substance laf)
216                splashScreen = new SplashScreenFrame();
217
218                // It's important to initialize AWT now (with InvokeNow(...) for instance) to avoid
219                // the JVM deadlock bug (id: 5104239). It happen when the AWT thread is initialized
220                // while others threads load some new library with ClassLoader.loadLibrary
221
222                // display splash NOW (don't use ThreadUtil as headless is still false here)
223                EventQueue.invokeAndWait(new Runnable()
224                {
225                    @Override
226                    public void run()
227                    {
228                        // display splash screen
229                        splashScreen.setVisible(true);
230                    }
231                });
232            }
233
234            // set LOCI debug level (do it immediately as it can quickly show some log messages)
235            loci.common.DebugTools.enableLogging("ERROR");
236
237            // fast start
238            new Thread(new Runnable()
239            {
240                @Override
241                public void run()
242                {
243                    // force image cache initialization so GUI won't wait after it (need preferences init)
244                    ImageCache.isEnabled();
245                }
246            }, "Initializer 1").start();
247            new Thread(new Runnable()
248            {
249                @Override
250                public void run()
251                {
252                    // initialize network (need preferences init)
253                    NetworkUtil.init();
254                }
255            }, "Initializer 2").start();
256            new Thread(new Runnable()
257            {
258                @Override
259                public void run()
260                {
261                    // load plugins classes (need preferences init)
262                    PluginLoader.reloadAsynch();
263                    WorkspaceLoader.reloadAsynch();
264                }
265            }, "Initializer 3").start();
266
267            try
268            {
269                // patches ImageJ classes (need to be done before instancing ImageJ)
270                ImageJPatcher.applyPatches();
271            }
272            catch (Throwable t)
273            {
274                System.err.println("Error while patching ImageJ classes:");
275                IcyExceptionHandler.showErrorMessage(t, false);
276            }
277
278            // build main interface
279            if (headless)
280                mainInterface = new MainInterfaceBatch();
281            else
282                mainInterface = new MainInterfaceGui();
283        }
284        catch (Throwable t)
285        {
286            // any error at this point is fatal
287            fatalError(t, headless);
288        }
289
290        if (!headless)
291        {
292            // do it on AWT thread NOW as this is what we want first
293            ThreadUtil.invokeNow(new Runnable()
294            {
295                @Override
296                public void run()
297                {
298                    try
299                    {
300                        // init Look And Feel (need mainInterface instance)
301                        LookAndFeelUtil.init();
302                        // init need "mainInterface" variable to be initialized
303                        getMainInterface().init();
304                    }
305                    catch (Throwable t)
306                    {
307                        // any error here is fatal
308                        fatalError(t, false);
309                    }
310                }
311            });
312        }
313        else
314        {
315            // simple main interface init
316            getMainInterface().init();
317        }
318
319        // splash screen initialized --> hide it
320        if (splashScreen != null)
321        {
322            // then do less important stuff later
323            ThreadUtil.invokeLater(new Runnable()
324            {
325                @Override
326                public void run()
327                {
328                    // we can now hide splash as we have interface
329                    splashScreen.dispose();
330                    splashScreen = null;
331                }
332            });
333        }
334
335        // show general informations
336        System.out.println(SystemUtil.getJavaName() + " " + SystemUtil.getJavaVersion() + " ("
337                + SystemUtil.getJavaArchDataModel() + " bit)");
338        System.out.println("Running on " + SystemUtil.getOSName() + " " + SystemUtil.getOSVersion() + " ("
339                + SystemUtil.getOSArch() + ")");
340        System.out.println("Number of processors : " + SystemUtil.getNumberOfCPUs());
341        System.out.println("System total memory : " + UnitUtil.getBytesString(SystemUtil.getTotalMemory()));
342        System.out.println("System available memory : " + UnitUtil.getBytesString(SystemUtil.getFreeMemory()));
343        System.out.println("Max java memory : " + UnitUtil.getBytesString(SystemUtil.getJavaMaxMemory()));
344        // image cache
345        if (ImageCache.isEnabled())
346        {
347            System.out.println("Image cache initialized (reserved memory = " + ApplicationPreferences.getCacheMemoryMB()
348                    + " MB, disk cache location = " + ApplicationPreferences.getCachePath() + ")");
349        }
350        else
351        {
352            System.err.println("Couldn't initialize image cache (cache is disabled)");
353            // disable virtual mode button from inspector
354            final InspectorPanel inspector = getMainInterface().getInspector();
355            if (inspector != null)
356                inspector.imageCacheDisabled();
357        }
358        if (headless)
359            System.out.println("Headless mode.");
360        System.out.println();
361
362        // initialize OSX specific GUI stuff
363        if (!headless && SystemUtil.isMac())
364            AppleUtil.init();
365        // initialize security
366        IcySecurityManager.init();
367        // initialize exception handler
368        IcyExceptionHandler.init();
369        // initialize action manager
370        ActionManager.init();
371        // prepare native library files (need preferences init)
372        nativeLibrariesInit();
373
374        // changed version ?
375        if (!ApplicationPreferences.getVersion().equals(Icy.version))
376        {
377            // not headless ?
378            if (!headless)
379            {
380                // display the new version information
381                final String changeLog = Icy.getChangeLog();
382
383                // show the new version frame
384                if (!StringUtil.isEmpty(changeLog))
385                {
386                    ThreadUtil.invokeNow(new Runnable()
387                    {
388                        @Override
389                        public void run()
390                        {
391                            new NewVersionFrame(Icy.getChangeLog());
392                        }
393                    });
394                }
395            }
396
397            // force check update for the new version
398            GeneralPreferences.setLastUpdateCheckTime(0);
399        }
400
401        // HTTPS not supported ?
402        if (!NetworkUtil.isHTTPSSupported())
403        {
404            // final String text1 = "Your version of java does not support HTTPS connection required by the future new web site.";
405            // final String text2 = "You need to upgrade java to 7u111 (Java 7) or 8u101 (Java 8) at least to be able to use online features in future.";
406            final String text1 = "Your version of java does not support HTTPS protocol which will be used soon by the new web site.";
407            final String text2 = "You need to upgrade your version of java to 7u111 (Java 7) or 8u101 (Java 8) at least to use online features (as search or plugin update) in future.";
408            // final String text2 = "You won't be able to use online features (as search or plugin update) in future until you update your version of java (Java
409            // 7u111 or Java
410            // 8u101 minimum).";
411
412            System.err.println("Warning: " + text1);
413            System.err.println(text2);
414
415            // TODO: change message when new web site is here
416            if (!Icy.getMainInterface().isHeadLess())
417                new ToolTipFrame("<html><b>WARNING:</b> " + text1 + "<br>" + text2 + "</html>", 0,
418                        "httpsNotSupportedWarning");
419            // new ToolTipFrame("<html><b>" + text1 + "<br>" + text2 + "</b></html>", 0, "httpsNotSupported");
420        }
421
422        final long currentTime = System.currentTimeMillis();
423        final long halfDayInterval = 1000 * 60 * 60 * 12;
424
425        // check only once per 12 hours slice
426        if (currentTime > (GeneralPreferences.getLastUpdateCheckTime() + halfDayInterval))
427        {
428            // check for core update
429            if (GeneralPreferences.getAutomaticUpdate())
430                IcyUpdater.checkUpdate(true);
431            // check for plugin update
432            if (PluginPreferences.getAutomaticUpdate())
433                PluginUpdater.checkUpdate(true);
434
435            // update last update check time
436            GeneralPreferences.setLastUpdateCheckTime(currentTime);
437        }
438
439        // update version info
440        ApplicationPreferences.setVersion(Icy.version);
441        // set LOCI debug level
442        // loci.common.DebugTools.enableLogging("ERROR");
443        // set OGL debug level
444        // SystemUtil.setProperty("jogl.verbose", "TRUE");
445        // SystemUtil.setProperty("jogl.debug", "TRUE");
446
447        System.out.println();
448        System.out.println("Icy Version " + version + " started !");
449        System.out.println();
450
451        checkParameters();
452
453        // handle startup arguments
454        if (startupImage != null)
455            Icy.getMainInterface().addSequence(Loader.loadSequence(FileUtil.getGenericPath(startupImage), 0, false));
456
457        // wait while updates are occurring before starting command line plugin...
458        while (PluginUpdater.isCheckingForUpdate() || PluginInstaller.isProcessing()
459                || WorkspaceInstaller.isProcessing())
460            ThreadUtil.sleep(1);
461
462        if (startupPluginName != null)
463        {
464            PluginLoader.waitWhileLoading();
465
466            final PluginDescriptor plugin = PluginLoader.getPlugin(startupPluginName);
467
468            if (plugin == null)
469            {
470                System.err.println("Could not launch plugin '" + startupPluginName + "': the plugin was not found.");
471                System.err.println("Be sure you correctly wrote the complete class name and respected the case.");
472                System.err.println("Ex: plugins.mydevid.analysis.MyPluginClass");
473            }
474            else
475                startupPlugin = PluginLauncher.start(plugin);
476        }
477
478        // headless mode ? we can exit now...
479        if (headless)
480            exit(false);
481    }
482
483    private static boolean handleAppArgs(String[] args)
484    {
485        final List<String> pluginArgsList = new ArrayList<String>();
486
487        startupImage = null;
488        startupPluginName = null;
489        startupPlugin = null;
490        boolean execute = false;
491        boolean headless = false;
492
493        // save the base arguments
494        Icy.args = args;
495
496        for (String arg : args)
497        {
498            // store plugin arguments
499            if (startupPluginName != null)
500                pluginArgsList.add(arg);
501            else if (execute)
502                startupPluginName = arg;
503            // special flag to disabled JCL (needed for development)
504            else if (arg.equalsIgnoreCase("--disableJCL") || arg.equalsIgnoreCase("-dJCL"))
505                PluginLoader.setJCLDisabled(true);
506            // headless mode
507            else if (arg.equalsIgnoreCase("--headless") || arg.equalsIgnoreCase("-hl"))
508                headless = true;
509            // disable splash-screen
510            else if (arg.equalsIgnoreCase("--nosplash") || arg.equalsIgnoreCase("-ns"))
511                noSplash = true;
512            // execute plugin
513            else if (arg.equalsIgnoreCase("--execute") || arg.equalsIgnoreCase("-x"))
514                execute = true;
515            // assume image name ?
516            else
517                startupImage = arg;
518        }
519
520        // save the plugin arguments
521        Icy.pluginArgs = pluginArgsList.toArray(new String[pluginArgsList.size()]);
522
523        return headless;
524    }
525
526    static void checkParameters()
527    {
528        // we are using a 32 bits JVM with a 64 bits OS --> warn the user
529        if (SystemUtil.isWindows64() && SystemUtil.is32bits())
530        {
531            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 !";
532
533            System.out.println("Warning: " + text);
534
535            if (!Icy.getMainInterface().isHeadLess())
536                new ToolTipFrame("<html>" + text + "</html>", 15, "badJavaArchTip");
537        }
538
539        // we are using java 6 on OSX --> warn the user
540        final double javaVersion = SystemUtil.getJavaVersionAsNumber();
541
542        if ((javaVersion > 0) && (javaVersion < 7d) && SystemUtil.isMac())
543        {
544            final String text = "It looks like you're using a old version of Java (1.6)<br>"
545                    + "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.";
546
547            System.out.println("Warning: " + text);
548
549            if (!Icy.getMainInterface().isHeadLess())
550                new ToolTipFrame("<html>" + text + "</html>", 15, "outdatedJavaOSX");
551        }
552
553        // detect bad memory setting
554        if ((ApplicationPreferences.getMaxMemoryMB() <= 128) && (ApplicationPreferences.getMaxMemoryMBLimit() > 256))
555        {
556            final String text = "Your maximum memory setting is low, you should increase it in Preferences.";
557
558            System.out.println("Warning: " + text);
559
560            if (!Icy.getMainInterface().isHeadLess())
561                new ToolTipFrame("<html>" + text + "</html>", 15, "lowMemoryTip");
562        }
563        else if (ApplicationPreferences.getMaxMemoryMB() < (ApplicationPreferences.getDefaultMemoryMB() / 2))
564        {
565            if (!Icy.getMainInterface().isHeadLess())
566            {
567                new ToolTipFrame(
568                        "<html><b>Tip:</b> you can increase your maximum memory in preferences setting.</html>", 15,
569                        "maxMemoryTip");
570            }
571        }
572
573        if (!Icy.getMainInterface().isHeadLess())
574        {
575            ToolTipFrame tooltip;
576
577            // welcome tip !
578            tooltip = new ToolTipFrame(
579                    "<html>Access the main menu by clicking on top left icon<br>" + "<img src=\""
580                            + Icy.class.getResource("/res/image/help/main_menu.png").toString() + "\" /></html>",
581                    30, "mainMenuTip");
582            tooltip.setSize(456, 240);
583
584            // new Image Cache !
585            tooltip = new ToolTipFrame("<html>" + "<img src=\""
586                    + Icy.class.getResource("/res/image/help/virtual_mode.jpg").toString() + "\" /><br>"
587                    + "This new button allow to enable/disable Icy <b>virtual mode</b>.<br><br>"
588                    + "Virtual mode will force all new created images to be in <i>virtual mode</i> which mean their data can be stored on disk to spare memory.<br>"
589                    + "Note that <i>virtual mode</i> is still experimental and <b>some plugins don't support it</b> (processed data can be lost) so use it carefully and only if you're running out of memory.<br>"
590                    + "<i>You can change the image caching settings in Icy preferences</i></html>", 30, "virtualMode");
591            tooltip.setSize(380, 240);
592        }
593    }
594
595    static void fatalError(Throwable t, boolean headless)
596    {
597        // hide splashScreen if needed
598        if ((splashScreen != null) && (splashScreen.isVisible()))
599            splashScreen.dispose();
600
601        // show error in console
602        IcyExceptionHandler.showErrorMessage(t, true);
603        // and show error in dialog if not headless
604        if (!headless)
605        {
606            JOptionPane.showMessageDialog(null, IcyExceptionHandler.getErrorMessage(t, true), "Fatal error",
607                    JOptionPane.ERROR_MESSAGE);
608        }
609
610        // exit with error code 1
611        System.exit(1);
612    }
613
614    /**
615     * Restart application with user confirmation
616     */
617    public static void confirmRestart()
618    {
619        confirmRestart(null);
620    }
621
622    /**
623     * Restart application with user confirmation (custom message)
624     */
625    public static void confirmRestart(String message)
626    {
627        final String mess;
628
629        if (StringUtil.isEmpty(message))
630            mess = "Application need to be restarted so changes can take effect. Do it now ?";
631        else
632            mess = message;
633
634        if (ConfirmDialog.confirm(mess))
635            // restart application now
636            exit(true);
637    }
638
639    /**
640     * Show announcement to restart application
641     */
642    public static void announceRestart()
643    {
644        announceRestart(null);
645    }
646
647    /**
648     * Show announcement to restart application (custom message)
649     */
650    public static void announceRestart(String message)
651    {
652        final String mess;
653
654        if (StringUtil.isEmpty(message))
655            mess = "Application need to be restarted so changes can take effet.";
656        else
657            mess = message;
658
659        if (Icy.getMainInterface().isHeadLess())
660        {
661            // just display this message
662            System.out.println(mess);
663        }
664        else
665        {
666            new AnnounceFrame(mess, "Restart Now", new Runnable()
667            {
668                @Override
669                public void run()
670                {
671                    // restart application now
672                    exit(true);
673                }
674            }, 20);
675        }
676    }
677
678    /**
679     * Returns <code>true</code> if application can exit.<br>
680     * Shows a confirmation dialog if setting requires it or if it's unsafe to exit now.
681     */
682    public static boolean canExit(boolean showConfirm)
683    {
684        // we first check if externals listeners allow existing
685        if (!getMainInterface().canExitExternal())
686            return false;
687
688        // headless mode --> allow exit
689        if (Icy.getMainInterface().isHeadLess())
690            return true;
691
692        // PluginInstaller or WorkspaceInstaller not running
693        final boolean safeExit = (!PluginInstaller.isProcessing()) && (!WorkspaceInstaller.isProcessing());
694
695        // not safe, need confirmation
696        if (!safeExit)
697        {
698            if (!ConfirmDialog.confirm("Quit the application",
699                    "Some processes are not yet completed, are you sure you want to quit ?",
700                    ConfirmDialog.YES_NO_CANCEL_OPTION))
701                return false;
702
703            return true;
704        }
705        else if (showConfirm && GeneralPreferences.getExitConfirm())
706        {
707            // we need user confirmation
708            if (!IdConfirmDialog.confirm("Quit the application ?", GeneralPreferences.ID_CONFIRM_EXIT))
709                return false;
710
711            return true;
712        }
713
714        return true;
715    }
716
717    /**
718     * Exit Icy, returns <code>true</code> if the operation should success.<br>
719     * Note that the method is asynchronous so you still have a bit of time to execute some stuff before the application
720     * actually exit.
721     */
722    public static boolean exit(final boolean restart)
723    {
724        // check we can exit application
725        if (!canExit(!restart))
726            return false;
727
728        // already existing
729        if (exiting && terminer.isAlive())
730        {
731            // set focus on exit frame
732            if (exitFrame != null)
733                exitFrame.requestFocus();
734            // return true;
735            return true;
736        }
737
738        // we don't want to be in EDT here and avoid BG runner
739        // as we test for BG runner completion
740        terminer = new Thread(new Runnable()
741        {
742            @Override
743            public void run()
744            {
745                // mark the application as exiting
746                exiting = true;
747
748                System.out.println("Exiting...");
749
750                final ImageJ ij = Icy.getMainInterface().getImageJ();
751
752                // clean ImageJ exit
753                if (ij != null)
754                    ij.quit();
755
756                // get main frame
757                final MainFrame mainFrame = Icy.getMainInterface().getMainFrame();
758
759                // disconnect from chat (not needed but preferred)
760                // if (mainFrame != null)
761                // mainFrame.getChat().disconnect("Icy closed");
762
763                // close all icyFrames (force wait completion)
764                ThreadUtil.invokeNow(new Runnable()
765                {
766                    @Override
767                    public void run()
768                    {
769                        // for (IcyFrame frame : IcyFrame.getAllFrames())
770                        // frame.close();
771                        // close all JInternalFrames
772                        final JDesktopPane desktopPane = Icy.getMainInterface().getDesktopPane();
773
774                        if (desktopPane != null)
775                        {
776                            for (JInternalFrame frame : desktopPane.getAllFrames())
777                            {
778                                // if (frame instanceof IcyInternalFrame)
779                                // {
780                                // final IcyInternalFrame iFrame = (IcyInternalFrame) frame;
781                                // if (!iFrame.isClosed())
782                                // iFrame.close(true);
783                                // if (iFrame.getDefaultCloseOperation() !=
784                                // WindowConstants.DISPOSE_ON_CLOSE)
785                                // iFrame.dispose();
786                                // }
787                                // else
788                                // {
789                                try
790                                {
791                                    frame.setClosed(true);
792                                }
793                                catch (PropertyVetoException e)
794                                {
795                                    // if (frame.getDefaultCloseOperation() !=
796                                    // WindowConstants.DISPOSE_ON_CLOSE)
797                                    frame.dispose();
798                                }
799                                // }
800                            }
801                        }
802
803                        // then close all external frames except main frame
804                        for (JFrame frame : Icy.getMainInterface().getExternalFrames())
805                        {
806                            if (frame != mainFrame)
807                            {
808                                if (frame instanceof IcyExternalFrame)
809                                {
810                                    final IcyExternalFrame iFrame = (IcyExternalFrame) frame;
811                                    iFrame.close();
812                                    if (iFrame.getDefaultCloseOperation() != WindowConstants.DISPOSE_ON_CLOSE)
813                                        iFrame.dispose();
814                                }
815                                else
816                                    frame.dispose();
817                            }
818                        }
819                    }
820                });
821
822                // stop daemon plugin
823                PluginLoader.stopDaemons();
824                // shutdown background processor after frame close
825                ThreadUtil.shutdown();
826
827                // headless mode
828                if (Icy.getMainInterface().isHeadLess())
829                {
830                    // final long start = System.currentTimeMillis();
831                    // // wait 10s max for background processors completed theirs tasks
832                    // while (!ThreadUtil.isShutdownAndTerminated() && ((System.currentTimeMillis()
833                    // - start) < 10 * 1000))
834                    // ThreadUtil.sleep(1);
835
836                    // wait that background processors completed theirs tasks
837                    while (!ThreadUtil.isShutdownAndTerminated())
838                        ThreadUtil.sleep(1);
839                }
840                else
841                {
842                    // need to create the exit frame in EDT
843                    ThreadUtil.invokeNow(new Runnable()
844                    {
845                        @Override
846                        public void run()
847                        {
848                            // create and display the exit frame
849                            exitFrame = new ExitFrame(EXIT_FORCE_DELAY);
850                        }
851                    });
852
853                    // wait that background processors completed theirs tasks
854                    while (!ThreadUtil.isShutdownAndTerminated() && !exitFrame.isForced())
855                        ThreadUtil.sleep(1);
856
857                    // need to dispose the exit frame in EDT (else we can have deadlock)
858                    ThreadUtil.invokeNow(new Runnable()
859                    {
860                        @Override
861                        public void run()
862                        {
863                            // can close the exit frame now
864                            exitFrame.dispose();
865                        }
866                    });
867                }
868
869                // need to dispose the main frame in EDT (else we can have deadlock)
870                ThreadUtil.invokeNow(new Runnable()
871                {
872                    @Override
873                    public void run()
874                    {
875                        // finally close the main frame
876                        if (mainFrame != null)
877                            mainFrame.dispose();
878                    }
879                });
880
881                // save preferences
882                IcyPreferences.save();
883                // save audit data
884                Audit.save();
885                // cache cleanup
886                ImageCache.end();
887
888                // clean up native library files
889                // unPrepareNativeLibraries();
890
891                // release lock
892                if (lock != null)
893                    SingleInstanceCheck.release(lock);
894
895                final boolean doUpdate = IcyUpdater.getWantUpdate();
896
897                // launch updater if needed
898                if (doUpdate || restart)
899                    IcyUpdater.launchUpdater(doUpdate, restart);
900
901                // good exit
902                System.exit(0);
903            }
904        });
905
906        terminer.setName("Icy Shutdown");
907        terminer.start();
908
909        return true;
910    }
911
912    /**
913     * @param force
914     * @deprecated use <code>exit(boolean)</code> instead
915     */
916    @Deprecated
917    public static boolean exit(final boolean restart, boolean force)
918    {
919        return exit(restart);
920    }
921
922    /**
923     * Return true is VTK library loaded.
924     */
925    public static boolean isVtkLibraryLoaded()
926    {
927        return vtkLibraryLoaded;
928    }
929
930    /**
931     * Return true is VTK library loaded.
932     */
933    public static boolean isItkLibraryLoaded()
934    {
935        return itkLibraryLoaded;
936    }
937
938    /**
939     * @deprecated Use {@link MainInterface#isHeadLess()} instead.
940     */
941    @Deprecated
942    public static boolean isHeadLess()
943    {
944        return getMainInterface().isHeadLess();
945    }
946
947    /**
948     * Return true is the application is currently exiting.
949     */
950    public static boolean isExiting()
951    {
952        return exiting;
953    }
954
955    /**
956     * Return the main Icy interface.
957     */
958    public static MainInterface getMainInterface()
959    {
960        // batch mode
961        if (mainInterface == null)
962            mainInterface = new MainInterfaceBatch();
963
964        return mainInterface;
965    }
966
967    /**
968     * Returns the command line arguments
969     */
970    public static String[] getCommandLineArgs()
971    {
972        return args;
973    }
974
975    /**
976     * Returns the plugin command line arguments
977     */
978    public static String[] getCommandLinePluginArgs()
979    {
980        return pluginArgs;
981    }
982
983    /**
984     * Clear the plugin command line arguments.<br>
985     * This method should be called after the launching plugin actually 'consumed' the startup
986     * arguments.
987     */
988    public static void clearCommandLinePluginArgs()
989    {
990        pluginArgs = new String[0];
991    }
992
993    /**
994     * Returns the startup plugin if any
995     */
996    public static Plugin getStartupPlugin()
997    {
998        return startupPlugin;
999    }
1000
1001    /**
1002     * Return content of the <code>CHANGELOG.txt</code> file
1003     */
1004    public static String getChangeLog()
1005    {
1006        if (FileUtil.exists("CHANGELOG.txt"))
1007            return new String(FileUtil.load("CHANGELOG.txt", false));
1008
1009        return "";
1010    }
1011
1012    /**
1013     * Return content of the <code>COPYING.txt</code> file
1014     */
1015    public static String getLicense()
1016    {
1017        if (FileUtil.exists("COPYING.txt"))
1018            return new String(FileUtil.load("COPYING.txt", false));
1019
1020        return "";
1021    }
1022
1023    /**
1024     * Return content of the <code>README.txt</code> file
1025     */
1026    public static String getReadMe()
1027    {
1028        if (FileUtil.exists("README.txt"))
1029            return new String(FileUtil.load("README.txt", false));
1030
1031        return "";
1032    }
1033
1034    /**
1035     * @deprecated Uses <code>Icy.getMainInterface().addSequence(Sequence)</code> instead.
1036     */
1037    @Deprecated
1038    public static void addSequence(final Sequence sequence)
1039    {
1040        Icy.getMainInterface().addSequence(sequence);
1041    }
1042
1043    static void nativeLibrariesInit()
1044    {
1045        // build the local native library path
1046        final String libPath = LIB_PATH + FileUtil.separator + SystemUtil.getOSArchIdString();
1047        final File libFile = new File(libPath);
1048
1049        // get all files in local native library path
1050        final File[] files = FileUtil.getFiles(libFile, null, true, true, false);
1051        final ArrayList<String> directories = new ArrayList<String>();
1052
1053        // add base local native library path to user library paths
1054        directories.add(libFile.getAbsolutePath());
1055        // add base temporary native library path to user library paths
1056        directories.add(SystemUtil.getTempLibraryDirectory());
1057
1058        for (File f : files)
1059        {
1060            if (f.isDirectory())
1061            {
1062                // add all directories to user library paths
1063                final String filePath = f.getAbsolutePath();
1064                if (!directories.contains(filePath))
1065                    directories.add(filePath);
1066            }
1067        }
1068
1069        // add lib folder for unix system
1070        if (SystemUtil.isUnix())
1071        {
1072            directories.add("/lib");
1073            directories.add("/usr/lib");
1074
1075            if (SystemUtil.is64bits())
1076            {
1077                directories.add("/lib64");
1078                directories.add("/lib/x86_64");
1079                directories.add("/lib/x86_64-linux-gnu");
1080                directories.add("/usr/lib64");
1081                directories.add("/usr/lib/x86_64");
1082                directories.add("/usr/lib/x86_64-linux-gnu");
1083            }
1084            else
1085            {
1086                directories.add("/lib/x86");
1087                directories.add("/lib/x86-linux-gnu");
1088                directories.add("/usr/lib/x86");
1089                directories.add("/usr/lib/x86-linux-gnu");
1090            }
1091        }
1092
1093        if (!SystemUtil.addToJavaLibraryPath(directories.toArray(new String[directories.size()])))
1094            System.err.println("Native libraries may not load correctly.");
1095
1096        // load native libraries
1097        loadVtkLibrary(libPath);
1098        // loadItkLibrary(libPath);
1099
1100        // disable native lib support for JAI as we don't provide them (for the moment)
1101        SystemUtil.setProperty("com.sun.media.jai.disableMediaLib", "true");
1102    }
1103
1104    private static void loadVtkLibrary(String libPath)
1105    {
1106        final String vtkLibPath = libPath + FileUtil.separator + "vtk";
1107
1108        // we load it directly from inner lib path if possible
1109        System.setProperty("vtk.lib.dir", vtkLibPath);
1110
1111        vtkLibraryLoaded = false;
1112        try
1113        {
1114            // if (SystemUtil.isUnix())
1115            // {
1116            // vtkNativeLibrary.LoadAllNativeLibraries();
1117            //
1118            // // assume VTK loaded if at least 1 native library is loaded
1119            // for (vtkNativeLibrary lib : vtkNativeLibrary.values())
1120            // if (lib.IsLoaded())
1121            // vtkLibraryLoaded = true;
1122            // }
1123            // else
1124            {
1125                loadLibrary(vtkLibPath, "vtkalglib");
1126                loadLibrary(vtkLibPath, "vtkexpat");
1127                loadLibrary(vtkLibPath, "vtkDICOMParser");
1128                loadLibrary(vtkLibPath, "vtkjpeg");
1129                loadLibrary(vtkLibPath, "vtkjsoncpp");
1130                loadLibrary(vtkLibPath, "vtkzlib");
1131                loadLibrary(vtkLibPath, "vtkoggtheora", false);
1132                loadLibrary(vtkLibPath, "vtkverdict");
1133                loadLibrary(vtkLibPath, "vtkpng");
1134
1135                loadLibrary(vtkLibPath, "vtkgl2ps", false); //
1136
1137                loadLibrary(vtkLibPath, "vtktiff");
1138                loadLibrary(vtkLibPath, "vtklibxml2");
1139                loadLibrary(vtkLibPath, "vtkproj4");
1140                loadLibrary(vtkLibPath, "vtksys");
1141                loadLibrary(vtkLibPath, "vtkfreetype");
1142                loadLibrary(vtkLibPath, "vtkmetaio");
1143                loadLibrary(vtkLibPath, "vtkftgl", false);
1144
1145                loadLibrary(vtkLibPath, "vtkftgl2", false); //
1146
1147                loadLibrary(vtkLibPath, "vtkglew", false);
1148                loadLibrary(vtkLibPath, "vtkCommonCore");
1149                loadLibrary(vtkLibPath, "vtkWrappingJava");
1150                loadLibrary(vtkLibPath, "vtkCommonSystem");
1151                loadLibrary(vtkLibPath, "vtkCommonMath");
1152                loadLibrary(vtkLibPath, "vtkCommonMisc");
1153                loadLibrary(vtkLibPath, "vtkCommonTransforms");
1154                if (SystemUtil.isMac())
1155                {
1156                    loadLibrary(vtkLibPath, "vtkhdf5.8.0.2", false);
1157                    loadLibrary(vtkLibPath, "vtkhdf5_hl.8.0.2", false);
1158                }
1159                else
1160                {
1161                    loadLibrary(vtkLibPath, "vtkhdf5", false);
1162                    loadLibrary(vtkLibPath, "vtkhdf5_hl", false);
1163                }
1164                loadLibrary(vtkLibPath, "vtkNetCDF");
1165                loadLibrary(vtkLibPath, "vtkNetCDF_cxx");
1166                loadLibrary(vtkLibPath, "vtkCommonDataModel");
1167                loadLibrary(vtkLibPath, "vtkCommonColor");
1168                loadLibrary(vtkLibPath, "vtkCommonComputationalGeometry");
1169                loadLibrary(vtkLibPath, "vtkCommonExecutionModel");
1170                loadLibrary(vtkLibPath, "vtkexoIIc");
1171                loadLibrary(vtkLibPath, "vtkFiltersVerdict");
1172                loadLibrary(vtkLibPath, "vtkFiltersProgrammable");
1173                loadLibrary(vtkLibPath, "vtkImagingMath");
1174                loadLibrary(vtkLibPath, "vtkIOCore");
1175                loadLibrary(vtkLibPath, "vtkIOEnSight");
1176                loadLibrary(vtkLibPath, "vtkIOVideo");
1177                loadLibrary(vtkLibPath, "vtkIOLegacy");
1178                loadLibrary(vtkLibPath, "vtkIONetCDF");
1179                loadLibrary(vtkLibPath, "vtkIOXMLParser");
1180                loadLibrary(vtkLibPath, "vtkIOXML");
1181                loadLibrary(vtkLibPath, "vtkIOImage");
1182                loadLibrary(vtkLibPath, "vtksqlite", false);
1183                loadLibrary(vtkLibPath, "vtkIOSQL");
1184                loadLibrary(vtkLibPath, "vtkIOMovie");
1185                loadLibrary(vtkLibPath, "vtkParallelCore");
1186                loadLibrary(vtkLibPath, "vtkImagingCore");
1187                loadLibrary(vtkLibPath, "vtkFiltersCore");
1188                loadLibrary(vtkLibPath, "vtkImagingColor");
1189                loadLibrary(vtkLibPath, "vtkImagingFourier");
1190                loadLibrary(vtkLibPath, "vtkImagingSources");
1191                loadLibrary(vtkLibPath, "vtkImagingHybrid");
1192                loadLibrary(vtkLibPath, "vtkImagingStatistics");
1193                loadLibrary(vtkLibPath, "vtkIOGeometry");
1194                loadLibrary(vtkLibPath, "vtkIOPLY");
1195                loadLibrary(vtkLibPath, "vtkFiltersSelection");
1196                loadLibrary(vtkLibPath, "vtkImagingGeneral");
1197                loadLibrary(vtkLibPath, "vtkImagingStencil");
1198                loadLibrary(vtkLibPath, "vtkImagingMorphological");
1199                loadLibrary(vtkLibPath, "vtkFiltersGeometry");
1200                loadLibrary(vtkLibPath, "vtkFiltersStatistics");
1201                loadLibrary(vtkLibPath, "vtkFiltersImaging");
1202                loadLibrary(vtkLibPath, "vtkIOLSDyna");
1203                loadLibrary(vtkLibPath, "vtkFiltersGeneral");
1204                loadLibrary(vtkLibPath, "vtkFiltersHyperTree");
1205                loadLibrary(vtkLibPath, "vtkFiltersSMP");
1206                loadLibrary(vtkLibPath, "vtkFiltersTexture");
1207                loadLibrary(vtkLibPath, "vtkFiltersAMR");
1208                loadLibrary(vtkLibPath, "vtkFiltersExtraction");
1209                loadLibrary(vtkLibPath, "vtkFiltersSources");
1210                loadLibrary(vtkLibPath, "vtkIOExodus");
1211                loadLibrary(vtkLibPath, "vtkFiltersGeneric");
1212                loadLibrary(vtkLibPath, "vtkFiltersModeling");
1213                loadLibrary(vtkLibPath, "vtkIOAMR");
1214                loadLibrary(vtkLibPath, "vtkFiltersFlowPaths");
1215                loadLibrary(vtkLibPath, "vtkInfovisCore");
1216                loadLibrary(vtkLibPath, "vtkIOInfovis");
1217                loadLibrary(vtkLibPath, "vtkInfovisLayout");
1218                loadLibrary(vtkLibPath, "vtkRenderingCore");
1219                loadLibrary(vtkLibPath, "vtkRenderingLOD");
1220                loadLibrary(vtkLibPath, "vtkRenderingImage");
1221                loadLibrary(vtkLibPath, "vtkRenderingFreeType");
1222                loadLibrary(vtkLibPath, "vtkDomainsChemistry");
1223
1224                loadLibrary(vtkLibPath, "vtkDomainsChemistryOpenGL2", false);
1225
1226                loadLibrary(vtkLibPath, "vtkInteractionStyle");
1227                loadLibrary(vtkLibPath, "vtkIOImport");
1228                loadLibrary(vtkLibPath, "vtkRenderingAnnotation");
1229                loadLibrary(vtkLibPath, "vtkRenderingLabel");
1230                loadLibrary(vtkLibPath, "vtkFiltersHybrid");
1231                loadLibrary(vtkLibPath, "vtkFiltersParallel");
1232                loadLibrary(vtkLibPath, "vtkFiltersParallelImaging");
1233                loadLibrary(vtkLibPath, "vtkIOMINC");
1234                loadLibrary(vtkLibPath, "vtkIOParallel");
1235                loadLibrary(vtkLibPath, "vtkRenderingVolume");
1236                loadLibrary(vtkLibPath, "vtkRenderingVolumeAMR", false);
1237                loadLibrary(vtkLibPath, "vtkInteractionWidgets");
1238                loadLibrary(vtkLibPath, "vtkInteractionImage");
1239                loadLibrary(vtkLibPath, "vtkViewsCore");
1240
1241                loadLibrary(vtkLibPath, "vtkRenderingOpenGL", false); //
1242
1243                loadLibrary(vtkLibPath, "vtkRenderingOpenGL2", false);
1244
1245                loadLibrary(vtkLibPath, "vtkRenderingLIC", false); //
1246                loadLibrary(vtkLibPath, "vtkRenderingVolumeOpenGL", false); //
1247
1248                loadLibrary(vtkLibPath, "vtkRenderingVolumeOpenGL2", false);
1249
1250                loadLibrary(vtkLibPath, "vtkRenderingContext2D");
1251                loadLibrary(vtkLibPath, "vtkRenderingContextOpenGL", false); //
1252
1253                loadLibrary(vtkLibPath, "vtkRenderingContextOpenGL2", false);
1254
1255                loadLibrary(vtkLibPath, "vtkRenderingGL2PS", false); //
1256
1257                loadLibrary(vtkLibPath, "vtkViewsContext2D");
1258                loadLibrary(vtkLibPath, "vtkGeovisCore");
1259                loadLibrary(vtkLibPath, "vtkIOExport");
1260                loadLibrary(vtkLibPath, "vtkChartsCore");
1261                loadLibrary(vtkLibPath, "vtkViewsInfovis");
1262                loadLibrary(vtkLibPath, "vtkViewsGeovis", false);
1263
1264                // JAVA wrapper
1265                loadLibrary(vtkLibPath, "vtkCommonCoreJava");
1266                loadLibrary(vtkLibPath, "vtkCommonSystemJava");
1267                loadLibrary(vtkLibPath, "vtkCommonMathJava");
1268                loadLibrary(vtkLibPath, "vtkCommonMiscJava");
1269                loadLibrary(vtkLibPath, "vtkCommonTransformsJava");
1270                loadLibrary(vtkLibPath, "vtkCommonDataModelJava");
1271                loadLibrary(vtkLibPath, "vtkCommonColorJava");
1272                loadLibrary(vtkLibPath, "vtkCommonComputationalGeometryJava");
1273                loadLibrary(vtkLibPath, "vtkCommonExecutionModelJava");
1274                loadLibrary(vtkLibPath, "vtkFiltersVerdictJava");
1275                loadLibrary(vtkLibPath, "vtkFiltersProgrammableJava");
1276                loadLibrary(vtkLibPath, "vtkImagingMathJava");
1277                loadLibrary(vtkLibPath, "vtkIOCoreJava");
1278                loadLibrary(vtkLibPath, "vtkIOEnSightJava");
1279                loadLibrary(vtkLibPath, "vtkIOVideoJava");
1280                loadLibrary(vtkLibPath, "vtkIOLegacyJava");
1281                loadLibrary(vtkLibPath, "vtkIONetCDFJava");
1282                loadLibrary(vtkLibPath, "vtkIOXMLParserJava");
1283                loadLibrary(vtkLibPath, "vtkIOXMLJava");
1284                loadLibrary(vtkLibPath, "vtkIOImageJava");
1285                loadLibrary(vtkLibPath, "vtkIOSQLJava");
1286                loadLibrary(vtkLibPath, "vtkIOMovieJava");
1287                loadLibrary(vtkLibPath, "vtkParallelCoreJava");
1288                loadLibrary(vtkLibPath, "vtkImagingCoreJava");
1289                loadLibrary(vtkLibPath, "vtkFiltersCoreJava");
1290                loadLibrary(vtkLibPath, "vtkImagingColorJava");
1291                loadLibrary(vtkLibPath, "vtkImagingFourierJava");
1292                loadLibrary(vtkLibPath, "vtkImagingSourcesJava");
1293                loadLibrary(vtkLibPath, "vtkImagingHybridJava");
1294                loadLibrary(vtkLibPath, "vtkImagingStatisticsJava");
1295                loadLibrary(vtkLibPath, "vtkIOGeometryJava");
1296                loadLibrary(vtkLibPath, "vtkIOPLYJava");
1297                loadLibrary(vtkLibPath, "vtkFiltersSelectionJava");
1298                loadLibrary(vtkLibPath, "vtkImagingGeneralJava");
1299                loadLibrary(vtkLibPath, "vtkImagingStencilJava");
1300                loadLibrary(vtkLibPath, "vtkImagingMorphologicalJava");
1301                loadLibrary(vtkLibPath, "vtkFiltersGeometryJava");
1302                loadLibrary(vtkLibPath, "vtkFiltersStatisticsJava");
1303                loadLibrary(vtkLibPath, "vtkFiltersImagingJava");
1304                loadLibrary(vtkLibPath, "vtkIOLSDynaJava");
1305                loadLibrary(vtkLibPath, "vtkFiltersGeneralJava");
1306                loadLibrary(vtkLibPath, "vtkFiltersHyperTreeJava");
1307                loadLibrary(vtkLibPath, "vtkFiltersSMPJava");
1308                loadLibrary(vtkLibPath, "vtkFiltersTextureJava");
1309                loadLibrary(vtkLibPath, "vtkFiltersAMRJava");
1310                loadLibrary(vtkLibPath, "vtkFiltersExtractionJava");
1311                loadLibrary(vtkLibPath, "vtkFiltersSourcesJava");
1312                loadLibrary(vtkLibPath, "vtkIOExodusJava");
1313                loadLibrary(vtkLibPath, "vtkFiltersGenericJava");
1314                loadLibrary(vtkLibPath, "vtkFiltersModelingJava");
1315                loadLibrary(vtkLibPath, "vtkIOAMRJava");
1316                loadLibrary(vtkLibPath, "vtkFiltersFlowPathsJava");
1317                loadLibrary(vtkLibPath, "vtkInfovisCoreJava");
1318                loadLibrary(vtkLibPath, "vtkIOInfovisJava");
1319                loadLibrary(vtkLibPath, "vtkInfovisLayoutJava");
1320                loadLibrary(vtkLibPath, "vtkRenderingCoreJava");
1321                loadLibrary(vtkLibPath, "vtkRenderingLODJava");
1322                loadLibrary(vtkLibPath, "vtkRenderingImageJava");
1323                loadLibrary(vtkLibPath, "vtkRenderingFreeTypeJava");
1324                loadLibrary(vtkLibPath, "vtkDomainsChemistryJava");
1325
1326                loadLibrary(vtkLibPath, "vtkDomainsChemistryOpenGL2Java", false);
1327
1328                loadLibrary(vtkLibPath, "vtkInteractionStyleJava");
1329                loadLibrary(vtkLibPath, "vtkIOImportJava");
1330                loadLibrary(vtkLibPath, "vtkRenderingAnnotationJava");
1331                loadLibrary(vtkLibPath, "vtkRenderingLabelJava");
1332                loadLibrary(vtkLibPath, "vtkFiltersHybridJava");
1333                loadLibrary(vtkLibPath, "vtkFiltersParallelJava");
1334                loadLibrary(vtkLibPath, "vtkFiltersParallelImagingJava");
1335                loadLibrary(vtkLibPath, "vtkIOMINCJava");
1336                loadLibrary(vtkLibPath, "vtkIOParallelJava");
1337                loadLibrary(vtkLibPath, "vtkRenderingVolumeJava");
1338                loadLibrary(vtkLibPath, "vtkRenderingVolumeAMRJava", false);
1339                loadLibrary(vtkLibPath, "vtkInteractionWidgetsJava");
1340                loadLibrary(vtkLibPath, "vtkInteractionImageJava");
1341                loadLibrary(vtkLibPath, "vtkViewsCoreJava");
1342                loadLibrary(vtkLibPath, "vtkRenderingOpenGLJava", false); //
1343
1344                loadLibrary(vtkLibPath, "vtkRenderingOpenGL2Java", false);
1345
1346                loadLibrary(vtkLibPath, "vtkRenderingLICJava", false); //
1347                loadLibrary(vtkLibPath, "vtkRenderingVolumeOpenGLJava", false); //
1348
1349                loadLibrary(vtkLibPath, "vtkRenderingVolumeOpenGL2Java", false);
1350
1351                loadLibrary(vtkLibPath, "vtkRenderingContext2DJava");
1352
1353                loadLibrary(vtkLibPath, "vtkRenderingContextOpenGLJava", false); //
1354
1355                loadLibrary(vtkLibPath, "vtkRenderingContextOpenGL2Java", false);
1356
1357                loadLibrary(vtkLibPath, "vtkRenderingGL2PSJava", false); //
1358
1359                loadLibrary(vtkLibPath, "vtkViewsContext2DJava");
1360                loadLibrary(vtkLibPath, "vtkGeovisCoreJava");
1361                loadLibrary(vtkLibPath, "vtkIOExportJava");
1362                loadLibrary(vtkLibPath, "vtkChartsCoreJava");
1363                loadLibrary(vtkLibPath, "vtkViewsInfovisJava");
1364                loadLibrary(vtkLibPath, "vtkViewsGeovisJava", false);
1365
1366                // VTK library successfully loaded
1367                vtkLibraryLoaded = true;
1368            }
1369
1370            // redirect vtk error log to file
1371            vtkNativeLibrary.DisableOutputWindow(new File("vtk.log"));
1372        }
1373        catch (Throwable e1)
1374        {
1375            IcyExceptionHandler.showErrorMessage(e1, false, false);
1376
1377            // // try to load the VTK way
1378            // try
1379            // {
1380            // System.out.print("Try to load VTK library using VTK method... ");
1381            //
1382            // vtkLibraryLoaded = vtkNativeLibrary.LoadAllNativeLibraries();
1383            //
1384            // if (vtkLibraryLoaded)
1385            // System.out.println("success !");
1386            // else
1387            // System.out.println("failed !");
1388            //
1389            // // redirect vtk error log to file
1390            // vtkNativeLibrary.DisableOutputWindow(new File("vtk.log"));
1391            // }
1392            // catch (Throwable e2)
1393            // {
1394            // IcyExceptionHandler.showErrorMessage(e2, false, false);
1395            // }
1396        }
1397
1398        if (vtkLibraryLoaded)
1399        {
1400            final String vv = new vtkVersion().GetVTKVersion();
1401
1402            System.out.println("VTK " + vv + " library successfully loaded...");
1403
1404            // final vtkJavaGarbageCollector vtkJavaGarbageCollector =
1405            // vtkObjectBase.JAVA_OBJECT_MANAGER
1406            // .getAutoGarbageCollector();
1407            //
1408            // set auto garbage collection for VTK (every 20 seconds should be enough)
1409            // probably not a good idea...
1410            // vtkJavaGarbageCollector.SetScheduleTime(5, TimeUnit.SECONDS);
1411            // vtkJavaGarbageCollector.SetAutoGarbageCollection(true);
1412        }
1413        else
1414        {
1415            System.out.println("Cannot load VTK library...");
1416
1417            if (SystemUtil.isMac())
1418            {
1419                final String osVer = SystemUtil.getOSVersion();
1420
1421                if (osVer.startsWith("10.6") || osVer.startsWith("10.5"))
1422                    System.out.println(
1423                            "VTK 6.3 is not supported on OSX " + osVer + ", version 10.7 or above is required.");
1424            }
1425        }
1426    }
1427
1428    private static void loadItkLibrary(String osDir)
1429    {
1430        final String itkLibDir = osDir + FileUtil.separator + "itk";
1431
1432        try
1433        {
1434            loadLibrary(itkLibDir, "SimpleITKJava", true);
1435
1436            System.out.println("SimpleITK library successfully loaded...");
1437            itkLibraryLoaded = true;
1438        }
1439        catch (Throwable e)
1440        {
1441            System.out.println("Cannot load SimpleITK library...");
1442        }
1443    }
1444
1445    private static void loadLibrary(String dir, String name, boolean mandatory, boolean showLog)
1446    {
1447        if (mandatory)
1448            SystemUtil.loadLibrary(dir, name);
1449        else
1450        {
1451            try
1452            {
1453                SystemUtil.loadLibrary(dir, name);
1454            }
1455            catch (Throwable e)
1456            {
1457                if (showLog)
1458                    System.out.println("cannot load " + name + ", skipping...");
1459            }
1460        }
1461    }
1462
1463    private static void loadLibrary(String dir, String name, boolean mandatory)
1464    {
1465        loadLibrary(dir, name, mandatory, false);
1466    }
1467
1468    private static void loadLibrary(String dir, String name)
1469    {
1470        loadLibrary(dir, name, true, false);
1471    }
1472
1473    static void nativeLibrariesShutdown()
1474    {
1475        // build the native local library path
1476        final String path = LIB_PATH + FileUtil.separator + SystemUtil.getOSArchIdString();
1477        // get file list (we don't want hidden files if any)
1478        File[] libraryFiles = FileUtil.getFiles(new File(path), null, true, false, false);
1479
1480        // remove previous copied files
1481        for (File libraryFile : libraryFiles)
1482        {
1483            // get file in root directory
1484            final File file = new File(libraryFile.getName());
1485            // invoke delete on exit if the file exists
1486            if (file.exists())
1487                file.deleteOnExit();
1488        }
1489
1490        // get file list from temporary native library path
1491        libraryFiles = FileUtil.getFiles(new File(SystemUtil.getTempLibraryDirectory()), null, true, false, false);
1492
1493        // remove previous copied files
1494        for (File libraryFile : libraryFiles)
1495        {
1496            // delete file
1497            if (!FileUtil.delete(libraryFile, false))
1498                libraryFile.deleteOnExit();
1499        }
1500    }
1501}