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.file.FileUtil; 022import icy.system.thread.SingleProcessor; 023import icy.system.thread.ThreadUtil; 024import icy.workspace.WorkspaceLoader.WorkspaceLoaderEvent.WorkspaceLoaderEventType; 025 026import java.io.File; 027import java.io.FileFilter; 028import java.util.ArrayList; 029import java.util.Collections; 030import java.util.EventListener; 031 032import javax.swing.event.EventListenerList; 033 034/** 035 * @author Stephane 036 */ 037public class WorkspaceLoader 038{ 039 public static interface WorkspaceLoaderListener extends EventListener 040 { 041 public void workspaceLoaderChanged(WorkspaceLoaderEvent e); 042 } 043 044 public static class WorkspaceLoaderEvent 045 { 046 public enum WorkspaceLoaderEventType 047 { 048 RELOADED 049 } 050 051 private final WorkspaceLoaderEventType type; 052 053 /** 054 * @param type 055 */ 056 public WorkspaceLoaderEvent(WorkspaceLoaderEventType type) 057 { 058 super(); 059 060 this.type = type; 061 } 062 063 /** 064 * @return the type 065 */ 066 public WorkspaceLoaderEventType getType() 067 { 068 return type; 069 } 070 071 @Override 072 public int hashCode() 073 { 074 return type.hashCode(); 075 } 076 077 @Override 078 public boolean equals(Object obj) 079 { 080 if (obj instanceof WorkspaceLoaderEvent) 081 { 082 final WorkspaceLoaderEvent e = (WorkspaceLoaderEvent) obj; 083 084 return (type == e.getType()); 085 } 086 087 return super.equals(obj); 088 } 089 } 090 091 public static final String WORKSPACE_PATH = "workspace"; 092 public static final String EXT = ".xml"; 093 094 /** 095 * static class 096 */ 097 private static final WorkspaceLoader instance = new WorkspaceLoader(); 098 099 /** 100 * Loaded workspace list 101 */ 102 private ArrayList<Workspace> workspaces; 103 104 /** 105 * listeners 106 */ 107 private final EventListenerList listeners; 108 109 /** 110 * internals 111 */ 112 private final Runnable reloader; 113 final SingleProcessor processor; 114 115 private boolean initialized; 116 117 /** 118 * @param path 119 */ 120 private WorkspaceLoader() 121 { 122 super(); 123 124 workspaces = new ArrayList<Workspace>(); 125 listeners = new EventListenerList(); 126 reloader = new Runnable() 127 { 128 @Override 129 public void run() 130 { 131 reloadInternal(); 132 } 133 }; 134 135 initialized = false; 136 137 processor = new SingleProcessor(true, "Local Workspace Loader"); 138 139 // don't load by default as we need Preferences to be ready first 140 } 141 142 public static void prepare() 143 { 144 if (!instance.initialized) 145 { 146 if (isLoading()) 147 waitWhileLoading(); 148 else 149 reload(); 150 } 151 } 152 153 /** 154 * Reload the list of installed workspaces (workspaces present in the "workspaces" directory). 155 * <br> 156 * Asynchronous version. 157 */ 158 public static void reloadAsynch() 159 { 160 instance.processor.submit(instance.reloader); 161 } 162 163 /** 164 * @deprecated Use {@link #reloadAsynch()} instead. 165 */ 166 @Deprecated 167 public static void reload_asynch() 168 { 169 reloadAsynch(); 170 } 171 172 /** 173 * Reload the list of installed workspaces (workspaces present in the "workspaces" directory) 174 */ 175 public static void reload() 176 { 177 reloadAsynch(); 178 waitWhileLoading(); 179 } 180 181 /** 182 * Reload the list of installed workspaces (workspaces present in the "workspaces" directory) 183 */ 184 void reloadInternal() 185 { 186 final ArrayList<Workspace> newWorkspaces = new ArrayList<Workspace>(); 187 188 final File[] files = FileUtil.getFiles(new File(FileUtil.getGenericPath(WORKSPACE_PATH)), new FileFilter() 189 { 190 @Override 191 public boolean accept(File file) 192 { 193 // only accept xml file 194 return FileUtil.getFileExtension(file.getPath(), true).toLowerCase().equals(EXT); 195 } 196 }, true, false, false); 197 198 for (File file : files) 199 { 200 final Workspace workspace = new Workspace(file); 201 202 // don't load the specific system workspace 203 if (!workspace.getName().equals(Workspace.WORKSPACE_SYSTEM_NAME)) 204 { 205 // empty workspace ? 206 if (workspace.isEmpty()) 207 { 208 // don't show this message for default workspace 209 // if (!workspace.getName().equals(Workspace.WORKSPACE_DEFAULT_NAME)) 210 System.err.println("Empty workspace '" + workspace.getName() + "' is not loaded"); 211 } 212 else 213 newWorkspaces.add(workspace); 214 } 215 } 216 217 // sort list 218 Collections.sort(newWorkspaces); 219 220 // set workspace list 221 workspaces = newWorkspaces; 222 223 // notify change 224 changed(); 225 } 226 227 /** 228 * @return the workspaceList 229 */ 230 public static ArrayList<Workspace> getWorkspaces() 231 { 232 prepare(); 233 234 synchronized (instance.workspaces) 235 { 236 // better to return a copy as we have async list loading 237 return new ArrayList<Workspace>(instance.workspaces); 238 } 239 } 240 241 /** 242 * @return the loading flag 243 */ 244 public static boolean isLoading() 245 { 246 return instance.processor.isProcessing(); 247 } 248 249 /** 250 * wait until loading completed 251 */ 252 public static void waitWhileLoading() 253 { 254 while (isLoading()) 255 ThreadUtil.sleep(10); 256 } 257 258 public static boolean isLoaded(Workspace workspace) 259 { 260 return (getWorkspace(workspace.getName()) != null); 261 } 262 263 public static Workspace getWorkspace(String name) 264 { 265 prepare(); 266 267 return Workspace.getWorkspace(getWorkspaces(), name); 268 } 269 270 private void changed() 271 { 272 initialized = true; 273 274 // workspace list has changed 275 fireEvent(new WorkspaceLoaderEvent(WorkspaceLoaderEventType.RELOADED)); 276 } 277 278 /** 279 * Add a listener 280 * 281 * @param listener 282 */ 283 public static void addListener(WorkspaceLoaderListener listener) 284 { 285 synchronized (instance.listeners) 286 { 287 instance.listeners.add(WorkspaceLoaderListener.class, listener); 288 } 289 } 290 291 /** 292 * Remove a listener 293 * 294 * @param listener 295 */ 296 public static void removeListener(WorkspaceLoaderListener listener) 297 { 298 synchronized (instance.listeners) 299 { 300 instance.listeners.remove(WorkspaceLoaderListener.class, listener); 301 } 302 } 303 304 /** 305 * fire event 306 */ 307 private void fireEvent(WorkspaceLoaderEvent e) 308 { 309 for (WorkspaceLoaderListener listener : listeners.getListeners(WorkspaceLoaderListener.class)) 310 listener.workspaceLoaderChanged(e); 311 } 312}