KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > io > VFSManager


1 /*
2  * VFSManager.java - Main class of virtual filesystem
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 2000, 2005 Slava Pestov
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */

22
23 package org.gjt.sp.jedit.io;
24
25 //{{{ Imports
26
import javax.swing.JOptionPane JavaDoc;
27 import javax.swing.SwingUtilities JavaDoc;
28 import java.awt.Component JavaDoc;
29 import java.awt.Frame JavaDoc;
30 import java.io.IOException JavaDoc;
31 import java.util.*;
32
33 import org.gjt.sp.jedit.gui.ErrorListDialog;
34 import org.gjt.sp.jedit.msg.VFSUpdate;
35 import org.gjt.sp.jedit.*;
36 import org.gjt.sp.util.Log;
37 import org.gjt.sp.util.WorkThreadPool;
38 import org.gjt.sp.util.StandardUtilities;
39 //}}}
40

41 /**
42  * jEdit's virtual filesystem allows it to transparently edit files
43  * stored elsewhere than the local filesystem, for example on an FTP
44  * site. See the {@link VFS} class for implementation details.<p>
45  *
46  * Note that most of the jEdit API is not thread-safe, so special care
47  * must be taken when making jEdit API calls. Also, it is not safe to
48  * call <code>SwingUtilities.invokeAndWait()</code> from a work request;
49  * it can cause a deadlock if the given runnable then later calls
50  * {@link #waitForRequests()}.
51  *
52  * @author Slava Pestov
53  * @version $Id: VFSManager.java 8286 2006-12-30 12:11:59Z kpouer $
54  */

55 public class VFSManager
56 {
57     /**
58      * The service type. See {@link org.gjt.sp.jedit.ServiceManager}.
59      * @since jEdit 4.2pre1
60      */

61     public static final String JavaDoc SERVICE = "org.gjt.sp.jedit.io.VFS";
62
63     //{{{ init() method
64
/**
65      * Do not call.
66      */

67     public static void init()
68     {
69         int count = jEdit.getIntegerProperty("ioThreadCount",4);
70         ioThreadPool = new WorkThreadPool("jEdit I/O",count);
71         JARClassLoader classLoader = new JARClassLoader();
72         for(int i = 0; i < ioThreadPool.getThreadCount(); i++)
73         {
74             ioThreadPool.getThread(i).setContextClassLoader(
75                 classLoader);
76         }
77     } //}}}
78

79     //{{{ start() method
80
/**
81      * Do not call.
82      */

83     public static void start()
84     {
85         ioThreadPool.start();
86     } //}}}
87

88     //{{{ VFS methods
89

90     //{{{ getFileVFS() method
91
/**
92      * Returns the local filesystem VFS.
93      * @since jEdit 2.5pre1
94      */

95     public static VFS getFileVFS()
96     {
97         return fileVFS;
98     } //}}}
99

100     //{{{ getUrlVFS() method
101
/**
102      * Returns the URL VFS.
103      * @since jEdit 2.5pre1
104      */

105     public static VFS getUrlVFS()
106     {
107         return urlVFS;
108     } //}}}
109

110     //{{{ getVFSByName() method
111
/**
112      * @deprecated Use <code>getVFSForProtocol()</code> instead.
113      */

114     public static VFS getVFSByName(String JavaDoc name)
115     {
116         // in new api, protocol always equals name
117
VFS vfs = (VFS)ServiceManager.getService(SERVICE,name);
118         if(vfs == null)
119             return vfsHash.get(name);
120         else
121             return vfs;
122     } //}}}
123

124     //{{{ getVFSForProtocol() method
125
/**
126      * Returns the VFS for the specified protocol.
127      * @param protocol The protocol
128      * @since jEdit 2.5pre1
129      */

130     public static VFS getVFSForProtocol(String JavaDoc protocol)
131     {
132         if(protocol.equals("file"))
133             return fileVFS;
134         else
135         {
136             VFS vfs = (VFS)ServiceManager.getService(SERVICE,protocol);
137             if(vfs == null)
138                 vfs = protocolHash.get(protocol);
139
140             if(vfs != null)
141                 return vfs;
142             else
143                 return urlVFS;
144         }
145     } //}}}
146

147     //{{{ getVFSForPath() method
148
/**
149      * Returns the VFS for the specified path.
150      * @param path The path
151      * @since jEdit 2.6pre4
152      */

153     public static VFS getVFSForPath(String JavaDoc path)
154     {
155         if(MiscUtilities.isURL(path))
156             return getVFSForProtocol(MiscUtilities.getProtocolOfURL(path));
157         else
158             return fileVFS;
159     } //}}}
160

161     //{{{ registerVFS() method
162
/**
163      * @deprecated Write a <code>services.xml</code> file instead;
164      * see {@link org.gjt.sp.jedit.ServiceManager}.
165      */

166     public static void registerVFS(String JavaDoc protocol, VFS vfs)
167     {
168         Log.log(Log.DEBUG,VFSManager.class,"Registered "
169             + vfs.getName() + " filesystem for "
170             + protocol + " protocol");
171         vfsHash.put(vfs.getName(),vfs);
172         protocolHash.put(protocol,vfs);
173     } //}}}
174

175     //{{{ getFilesystems() method
176
/**
177      * @deprecated Use <code>getVFSs()</code> instead.
178      */

179     public static Enumeration<VFS> getFilesystems()
180     {
181         return vfsHash.elements();
182     } //}}}
183

184     //{{{ getVFSs() method
185
/**
186      * Returns a list of all registered filesystems.
187      * @since jEdit 4.2pre1
188      */

189     public static String JavaDoc[] getVFSs()
190     {
191         // the sooner ppl move to the new api, the less we'll need
192
// crap like this
193
List<String JavaDoc> returnValue = new LinkedList<String JavaDoc>();
194         String JavaDoc[] newAPI = ServiceManager.getServiceNames(SERVICE);
195         if(newAPI != null)
196         {
197             for(int i = 0; i < newAPI.length; i++)
198             {
199                 returnValue.add(newAPI[i]);
200             }
201         }
202         Enumeration<String JavaDoc> oldAPI = vfsHash.keys();
203         while(oldAPI.hasMoreElements())
204             returnValue.add(oldAPI.nextElement());
205         return returnValue.toArray(new String JavaDoc[returnValue.size()]);
206     } //}}}
207

208     //}}}
209

210     //{{{ I/O request methods
211

212     //{{{ getIOThreadPool() method
213
/**
214      * Returns the I/O thread pool.
215      */

216     public static WorkThreadPool getIOThreadPool()
217     {
218         return ioThreadPool;
219     } //}}}
220

221     //{{{ waitForRequests() method
222
/**
223      * Returns when all pending requests are complete.
224      * @since jEdit 2.5pre1
225      */

226     public static void waitForRequests()
227     {
228         ioThreadPool.waitForRequests();
229     } //}}}
230

231     //{{{ errorOccurred() method
232
/**
233      * Returns if the last request caused an error.
234      */

235     public static boolean errorOccurred()
236     {
237         return error;
238     } //}}}
239

240     //{{{ getRequestCount() method
241
/**
242      * Returns the number of pending I/O requests.
243      */

244     public static int getRequestCount()
245     {
246         return ioThreadPool.getRequestCount();
247     } //}}}
248

249     //{{{ runInAWTThread() method
250
/**
251      * Executes the specified runnable in the AWT thread once all
252      * pending I/O requests are complete.
253      * @since jEdit 2.5pre1
254      */

255     public static void runInAWTThread(Runnable JavaDoc run)
256     {
257         ioThreadPool.addWorkRequest(run,true);
258     } //}}}
259

260     //{{{ runInWorkThread() method
261
/**
262      * Executes the specified runnable in one of the I/O threads.
263      * @since jEdit 2.6pre2
264      */

265     public static void runInWorkThread(Runnable JavaDoc run)
266     {
267         ioThreadPool.addWorkRequest(run,false);
268     } //}}}
269

270     //}}}
271

272     //{{{ error() method
273
/**
274      * Handle an I/O error.
275      * @since jEdit 4.3pre3
276      */

277     public static void error(IOException JavaDoc e, String JavaDoc path, Component JavaDoc comp)
278     {
279         Log.log(Log.ERROR,VFSManager.class,e);
280         VFSManager.error(comp,path,"ioerror",new String JavaDoc[] { e.toString() });
281     } //}}}
282

283     //{{{ error() method
284
/**
285      * @deprecated Call the other <code>error()</code> method instead.
286      */

287     public static void error(final Component JavaDoc comp, final String JavaDoc error, final Object JavaDoc[] args)
288     {
289         // if we are already in the AWT thread, take a shortcut
290
if(SwingUtilities.isEventDispatchThread())
291         {
292             GUIUtilities.error(comp,error,args);
293             return;
294         }
295
296         // the 'error' chicanery ensures that stuff like:
297
// VFSManager.waitForRequests()
298
// if(VFSManager.errorOccurred())
299
// ...
300
// will work (because the below runnable will only be
301
// executed in the next event)
302
VFSManager.error = true;
303
304         runInAWTThread(new Runnable JavaDoc()
305         {
306             public void run()
307             {
308                 VFSManager.error = false;
309
310                 if(comp == null || !comp.isShowing())
311                     GUIUtilities.error(null,error,args);
312                 else
313                     GUIUtilities.error(comp,error,args);
314             }
315         });
316     } //}}}
317

318     //{{{ error() method
319
/**
320      * Reports an I/O error.
321      *
322      * @param comp The component
323      * @param path The path name that caused the error
324      * @param messageProp The error message property name
325      * @param args Positional parameters
326      * @since jEdit 4.0pre3
327      */

328     public static void error(Component JavaDoc comp,
329         final String JavaDoc path,
330         String JavaDoc messageProp,
331         Object JavaDoc[] args)
332     {
333         final Frame JavaDoc frame = JOptionPane.getFrameForComponent(comp);
334
335         synchronized(errorLock)
336         {
337             error = true;
338
339             errors.add(new ErrorListDialog.ErrorEntry(
340                 path,messageProp,args));
341
342             if(errors.size() == 1)
343             {
344                 
345
346                 VFSManager.runInAWTThread(new Runnable JavaDoc()
347                 {
348                     public void run()
349                     {
350                         String JavaDoc caption = jEdit.getProperty(
351                             "ioerror.caption" + (errors.size() == 1
352                             ? "-1" : ""),new Integer JavaDoc[] {
353                             Integer.valueOf(errors.size())});
354                         new ErrorListDialog(
355                             frame.isShowing()
356                             ? frame
357                             : jEdit.getFirstView(),
358                             jEdit.getProperty("ioerror.title"),
359                             caption,errors,false);
360                         errors.clear();
361                         error = false;
362                     }
363                 });
364             }
365         }
366     } //}}}
367

368     //{{{ sendVFSUpdate() method
369
/**
370      * Sends a VFS update message.
371      * @param vfs The VFS
372      * @param path The path that changed
373      * @param parent True if an update should be sent for the path's
374      * parent too
375      * @since jEdit 2.6pre4
376      */

377     public static void sendVFSUpdate(VFS vfs, String JavaDoc path, boolean parent)
378     {
379         if(parent)
380         {
381             sendVFSUpdate(vfs,vfs.getParentOfPath(path),false);
382             sendVFSUpdate(vfs,path,false);
383         }
384         else
385         {
386             // have to do this hack until VFSPath class is written
387
if(path.length() != 1 && (path.endsWith("/")
388                 || path.endsWith(java.io.File.separator)))
389                 path = path.substring(0,path.length() - 1);
390
391             synchronized(vfsUpdateLock)
392             {
393                 for(int i = 0; i < vfsUpdates.size(); i++)
394                 {
395                     VFSUpdate msg = vfsUpdates.get(i);
396                     if(msg.getPath().equals(path))
397                     {
398                         // don't send two updates
399
// for the same path
400
return;
401                     }
402                 }
403
404                 vfsUpdates.add(new VFSUpdate(path));
405
406                 if(vfsUpdates.size() == 1)
407                 {
408                     // we were the first to add an update;
409
// add update sending runnable to AWT
410
// thread
411
VFSManager.runInAWTThread(new SendVFSUpdatesSafely());
412                 }
413             }
414         }
415     } //}}}
416

417     //{{{ SendVFSUpdatesSafely class
418
static class SendVFSUpdatesSafely implements Runnable JavaDoc
419     {
420         public void run()
421         {
422             synchronized(vfsUpdateLock)
423             {
424                 // the vfs browser has what you might call
425
// a design flaw, it doesn't update properly
426
// unless the vfs update for a parent arrives
427
// before any updates for the children. sorting
428
// the list alphanumerically guarantees this.
429
Collections.sort(vfsUpdates,
430                     new StandardUtilities.StringCompare()
431                 );
432                 for(int i = 0; i < vfsUpdates.size(); i++)
433                 {
434                     EditBus.send(vfsUpdates.get(i));
435                 }
436
437                 vfsUpdates.clear();
438             }
439         }
440     } //}}}
441

442     //{{{ Private members
443

444     //{{{ Static variables
445
private static WorkThreadPool ioThreadPool;
446     private static VFS fileVFS;
447     private static VFS urlVFS;
448     private static final Hashtable<String JavaDoc, VFS> vfsHash;
449     private static final Map<String JavaDoc, VFS> protocolHash;
450     private static boolean error;
451     private static final Object JavaDoc errorLock = new Object JavaDoc();
452     private static final Vector<ErrorListDialog.ErrorEntry> errors;
453     private static final Object JavaDoc vfsUpdateLock = new Object JavaDoc();
454     private static final List<VFSUpdate> vfsUpdates;
455     //}}}
456

457     //{{{ Class initializer
458
static
459     {
460         errors = new Vector<ErrorListDialog.ErrorEntry>();
461         fileVFS = new FileVFS();
462         urlVFS = new UrlVFS();
463         vfsHash = new Hashtable<String JavaDoc, VFS>();
464         protocolHash = new Hashtable<String JavaDoc, VFS>();
465         vfsUpdates = new ArrayList<VFSUpdate>(10);
466     } //}}}
467

468     private VFSManager() {}
469     //}}}
470
}
471
Popular Tags