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.workspace;
020
021import icy.network.NetworkUtil;
022import icy.network.URLUtil;
023import icy.preferences.RepositoryPreferences;
024import icy.preferences.RepositoryPreferences.RepositoryInfo;
025import icy.system.IcyExceptionHandler;
026import icy.util.StringUtil;
027import icy.util.XMLUtil;
028
029import java.util.ArrayList;
030import java.util.Collections;
031import java.util.EventListener;
032
033import javax.swing.event.EventListenerList;
034
035import org.w3c.dom.Document;
036import org.w3c.dom.Node;
037
038/**
039 * @author Stephane
040 */
041public class WorkspaceRepositoryLoader
042{
043    public static interface WorkspaceRepositoryLoaderListener extends EventListener
044    {
045        public void workspaceRepositeryLoaderChanged();
046    }
047
048    private class LoadRunner extends Thread
049    {
050        public LoadRunner()
051        {
052            super("Online workspace loader");
053        }
054
055        @Override
056        public void run()
057        {
058            // no Internet connection ?
059            if (!NetworkUtil.hasInternetAccess())
060            {
061                failed = true;
062                return;
063            }
064
065            final ArrayList<Workspace> newWorkspaces = new ArrayList<Workspace>();
066
067            failed = false;
068            try
069            {
070                final ArrayList<RepositoryInfo> repositories = RepositoryPreferences.getRepositeries();
071
072                // load online workspace from all active repositories
073                for (RepositoryInfo repoInfo : repositories)
074                {
075                    if (interrupted())
076                        return;
077
078                    if (repoInfo.isEnabled())
079                    {
080                        final ArrayList<Workspace> workspacesRepos = loadInternal(repoInfo);
081
082                        if (workspacesRepos == null)
083                        {
084                            failed = true;
085                            return;
086                        }
087
088                        newWorkspaces.addAll(workspacesRepos);
089                    }
090                }
091
092                // sort list
093                Collections.sort(newWorkspaces);
094
095                synchronized (workspaces)
096                {
097                    workspaces = newWorkspaces;
098                }
099            }
100            catch (Exception e)
101            {
102                IcyExceptionHandler.showErrorMessage(e, true);
103                failed = true;
104                return;
105            }
106
107            changed();
108        }
109    }
110
111    private static final String ID_ROOT = "workspaces";
112    private static final String ID_WORKSPACE = "workspace";
113    private static final String ID_PATH = "path";
114
115    /**
116     * static class
117     */
118    private static final WorkspaceRepositoryLoader instance = new WorkspaceRepositoryLoader();
119
120    /**
121     * Online workspace list
122     */
123    ArrayList<Workspace> workspaces;
124
125    /**
126     * internal
127     */
128    boolean failed;
129
130    private LoadRunner loadRunner;
131
132    /**
133     * listeners
134     */
135    private final EventListenerList listeners;
136
137    /**
138     * static class
139     */
140    private WorkspaceRepositoryLoader()
141    {
142        super();
143
144        workspaces = new ArrayList<Workspace>();
145        listeners = new EventListenerList();
146        failed = false;
147
148        // initial loading
149        startLoad();
150    }
151
152    /**
153     * Return the workspaces file list from a repository URL
154     */
155    public static ArrayList<String> getWorkspaceFiles(RepositoryInfo repos)
156    {
157        final ArrayList<String> result = new ArrayList<String>();
158        final Document document = XMLUtil.loadDocument(repos.getLocation(), repos.getAuthenticationInfo(), true);
159
160        if (document != null)
161        {
162            // get workspaces node
163            final Node workspacesNode = XMLUtil.getElement(document.getDocumentElement(), ID_ROOT);
164
165            // workspaces node found
166            if (workspacesNode != null)
167            {
168                final ArrayList<Node> nodes = XMLUtil.getChildren(workspacesNode, ID_WORKSPACE);
169
170                for (Node node : nodes)
171                {
172                    final String path = XMLUtil.getElementValue(node, ID_PATH, "");
173
174                    if (!StringUtil.isEmpty(path))
175                        result.add(path);
176                }
177            }
178        }
179        else
180        {
181            if (!NetworkUtil.hasInternetAccess())
182                System.out.println("You are not connected to internet.");
183            else
184                System.out.println("Can't access repository '" + repos.getName() + "'");
185        }
186
187        return result;
188    }
189
190    /**
191     * Start loading process
192     */
193    private void startLoad()
194    {
195        loadRunner = new LoadRunner();
196        loadRunner.start();
197    }
198
199    /**
200     * Reload all online workspaces from all active repositories (old list is cleared)
201     */
202    public static void reload()
203    {
204        // request interrupt
205        instance.loadRunner.interrupt();
206
207        // We don't need to wait... can make the preferences panel to lag on validation
208//        // wait for end processing
209//        try
210//        {
211//            instance.loadRunner.join();
212//        }
213//        catch (InterruptedException e)
214//        {
215//            // ignore
216//        }
217
218        // start it again
219        instance.startLoad();
220    }
221
222    /**
223     * Load and return the list of online workspaces located at specified repository url
224     */
225    ArrayList<Workspace> loadInternal(RepositoryInfo repos)
226    {
227        final ArrayList<String> paths = getWorkspaceFiles(repos);
228
229        // error while retrieving paths ?
230        if (paths == null)
231        {
232            if (!NetworkUtil.hasInternetAccess())
233                System.out.println("You are not connected to internet.");
234            else
235                System.out.println("Can't access repository '" + repos.getName() + "'");
236
237            return null;
238        }
239
240        final ArrayList<Workspace> result = new ArrayList<Workspace>();
241
242        for (String path : paths)
243        {
244            try
245            {
246                final Workspace workspace = new Workspace(URLUtil.getURL(path), repos);
247
248                if (!workspace.isEmpty())
249                    result.add(workspace);
250            }
251            catch (Exception e)
252            {
253                System.err.println("WorkspaceRepositoryLoader.load('" + repos.getLocation() + "') error :");
254                IcyExceptionHandler.showErrorMessage(e, false);
255            }
256        }
257
258        return result;
259    }
260
261    /**
262     * @return the workspaceList
263     */
264    public static ArrayList<Workspace> getWorkspaces()
265    {
266        synchronized (instance.workspaces)
267        {
268            return new ArrayList<Workspace>(instance.workspaces);
269        }
270    }
271
272    public static Workspace getWorkspace(String className)
273    {
274        synchronized (instance.workspaces)
275        {
276            return Workspace.getWorkspace(instance.workspaces, className);
277        }
278    }
279
280    /**
281     * Return the workspace list from the specified repository
282     */
283    public static ArrayList<Workspace> getWorkspaces(RepositoryInfo repos)
284    {
285        final ArrayList<Workspace> result = new ArrayList<Workspace>();
286
287        synchronized (instance.workspaces)
288        {
289            for (Workspace workspace : instance.workspaces)
290                if (workspace.getRepository().equals(repos))
291                    result.add(workspace);
292        }
293
294        return result;
295    }
296
297    /**
298     * @return the loaded
299     */
300    public static boolean isLoading()
301    {
302        return instance.loadRunner.isAlive();
303    }
304
305    /**
306     * wait until loading completed
307     */
308    public static void waitWhileLoading()
309    {
310        try
311        {
312            instance.loadRunner.join();
313        }
314        catch (InterruptedException e)
315        {
316            // ignore
317        }
318    }
319
320    /**
321     * return true if an error occurred during the workspace loading process
322     */
323    public static boolean failed()
324    {
325        return instance.failed;
326    }
327
328    /**
329     * workspace list has changed
330     */
331    void changed()
332    {
333        fireEvent();
334    }
335
336    /**
337     * Add a listener
338     * 
339     * @param listener
340     */
341    public static void addListener(WorkspaceRepositoryLoaderListener listener)
342    {
343        synchronized (instance.listeners)
344        {
345            instance.listeners.add(WorkspaceRepositoryLoaderListener.class, listener);
346        }
347    }
348
349    /**
350     * Remove a listener
351     * 
352     * @param listener
353     */
354    public static void removeListener(WorkspaceRepositoryLoaderListener listener)
355    {
356        synchronized (instance.listeners)
357        {
358            instance.listeners.remove(WorkspaceRepositoryLoaderListener.class, listener);
359        }
360    }
361
362    /**
363     * fire event
364     */
365    private void fireEvent()
366    {
367        for (WorkspaceRepositoryLoaderListener listener : listeners
368                .getListeners(WorkspaceRepositoryLoaderListener.class))
369            listener.workspaceRepositeryLoaderChanged();
370    }
371
372}