001/*
002 * Copyright 2010-2015 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.plugin;
020
021import icy.gui.frame.progress.AnnounceFrame;
022import icy.gui.frame.progress.CancelableProgressFrame;
023import icy.gui.frame.progress.ProgressFrame;
024import icy.gui.plugin.PluginUpdateFrame;
025import icy.main.Icy;
026import icy.network.NetworkUtil;
027import icy.system.thread.ThreadUtil;
028
029import java.util.ArrayList;
030import java.util.List;
031
032/**
033 * Plugin updater class.
034 * 
035 * @author Stephane.D
036 */
037public class PluginUpdater
038{
039    private static final int ANNOUNCE_SHOWTIME = 15;
040
041    // internal
042    private static boolean silent;
043    private static boolean checking = false;
044    private static Runnable checker = new Runnable()
045    {
046        @Override
047        public void run()
048        {
049            processCheckUpdate();
050        }
051    };
052
053    /**
054     * return true if we are currently checking for update
055     */
056    public static boolean isCheckingForUpdate()
057    {
058        return checking || ThreadUtil.hasWaitingBgSingleTask(checker);
059    }
060
061    /**
062     * Do the check update process
063     */
064    public static void checkUpdate(boolean silent)
065    {
066        if (!isCheckingForUpdate())
067        {
068            PluginUpdater.silent = silent;
069            ThreadUtil.bgRunSingle(checker);
070        }
071    }
072
073    /**
074     * @deprecated Use {@link #checkUpdate(boolean)} instead
075     */
076    @Deprecated
077    public static void checkUpdate(boolean showProgress, boolean auto)
078    {
079        checkUpdate(!showProgress || auto);
080    }
081
082    /**
083     * Get update for the specified plugin.
084     * 
085     * @param plugin
086     *        local plugin we are looking update for
087     * @return
088     *         plugin descriptor of update if any (null if no update)
089     */
090    public static PluginDescriptor getUpdate(PluginDescriptor plugin)
091    {
092        // don't check update for kernel plugin
093        if (plugin.isKernelPlugin())
094            return null;
095
096        // find equivalent online plugins
097        final List<PluginDescriptor> onlinePlugins = PluginRepositoryLoader.getPlugins(plugin.getClassName());
098        final PluginDescriptor onlinePlugin;
099
100        // get the last version found
101        if (onlinePlugins.size() > 0)
102        {
103            PluginDescriptor lastVersion = null;
104
105            for (PluginDescriptor currentVersion : onlinePlugins)
106                if ((lastVersion == null) || currentVersion.isNewer(lastVersion))
107                    lastVersion = currentVersion;
108
109            onlinePlugin = lastVersion;
110        }
111        else
112            // not found in repositories
113            onlinePlugin = null;
114
115        // we have an update available ?
116        if ((onlinePlugin != null) && onlinePlugin.getVersion().isGreater(plugin.getVersion()))
117            return onlinePlugin;
118
119        // random forced update
120        // if (Random.nextBoolean())
121        // return onlinePlugin;
122
123        return null;
124    }
125
126    /**
127     * Update the specified list of plugins.
128     */
129    public static void updatePlugins(List<PluginDescriptor> plugins, boolean showProgress)
130    {
131        try
132        {
133            // update plugins with ordered dependencies
134            for (PluginDescriptor plugin : PluginInstaller.orderDependencies(plugins))
135                PluginInstaller.install(plugin, showProgress);
136        }
137        finally
138        {
139            PluginLoader.reloadAsynch();
140        }
141    }
142
143    /**
144     * Check for plugins update process (synchronized method)
145     */
146    public static synchronized void processCheckUpdate()
147    {
148        checking = true;
149        try
150        {
151            final List<PluginDescriptor> toInstallPlugins = new ArrayList<PluginDescriptor>();
152            final List<PluginDescriptor> localPlugins = PluginLoader.getPlugins(false);
153            final ProgressFrame checkingFrame;
154
155            if (!silent && !Icy.getMainInterface().isHeadLess())
156                checkingFrame = new CancelableProgressFrame("checking for plugins update...");
157            else
158                checkingFrame = null;
159            try
160            {
161                // reload online plugins from all active repositories
162                PluginRepositoryLoader.reload();
163                // wait for basic infos
164                PluginRepositoryLoader.waitLoaded();
165
166                if (PluginRepositoryLoader.failed())
167                {
168                    if (!silent && !Icy.getMainInterface().isHeadLess())
169                    {
170                        if (!NetworkUtil.hasInternetAccess())
171                            new AnnounceFrame("You are not connected to internet.", 10);
172                        else
173                            new AnnounceFrame("Can't access the repositories... You should verify your connection.",
174                                    10);
175                    }
176
177                    return;
178                }
179
180                for (PluginDescriptor localPlugin : localPlugins)
181                {
182                    // find update
183                    final PluginDescriptor onlinePlugin = getUpdate(localPlugin);
184
185                    // update found, add to the list
186                    if (onlinePlugin != null)
187                    {
188                        // we load complete descriptor so we will have the changeslog
189                        onlinePlugin.loadDescriptor();
190                        toInstallPlugins.add(onlinePlugin);
191                    }
192                }
193
194                // TODO: incorrect java version cannot be fixed with plugin udpate !
195                final List<PluginDescriptor> onlinePlugins = PluginRepositoryLoader.getPlugins();
196
197                for (PluginDescriptor onlinePlugin : onlinePlugins)
198                {
199                    // we found a plugin which is installed but not correctly loaded
200                    // so we try to reinstall it
201                    if (onlinePlugin.isInstalled() && !PluginLoader.isLoaded(onlinePlugin.getClassName()))
202                    {
203                        // we load complete descriptor so we will have the changeslog
204                        onlinePlugin.loadDescriptor();
205                        toInstallPlugins.add(onlinePlugin);
206                    }
207                }
208            }
209            finally
210            {
211                if (checkingFrame != null)
212                    checkingFrame.close();
213            }
214
215            // some updates availables ?
216            if (!toInstallPlugins.isEmpty())
217            {
218                // silent update or headless mode
219                if (silent || Icy.getMainInterface().isHeadLess())
220                {
221                    // automatically install all updates (orderer depending dependencies)
222                    updatePlugins(toInstallPlugins, true);
223                }
224                else
225                {
226                    // show announcement for 15 seconds
227                    new AnnounceFrame(toInstallPlugins.size() + " plugin update are available", "View", new Runnable()
228                    {
229                        @Override
230                        public void run()
231                        {
232                            // show pluginInstaller frame
233                            new PluginUpdateFrame(toInstallPlugins);
234                        }
235                    }, ANNOUNCE_SHOWTIME);
236                }
237            }
238            else
239            {
240                // inform that there is no plugin update available
241                if (!silent && !Icy.getMainInterface().isHeadLess())
242                    new AnnounceFrame("No plugin udpate available", 10);
243            }
244        }
245        finally
246        {
247            checking = false;
248        }
249    }
250}