PageRenderTime 34ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre4/org/gjt/sp/jedit/io/VFSManager.java

#
Java | 450 lines | 241 code | 44 blank | 165 comment | 28 complexity | e4255b871dd8ca0a6ffa70c208089d3f MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  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, 2003 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. package org.gjt.sp.jedit.io;
  23. //{{{ Imports
  24. import java.util.Enumeration;
  25. import java.util.Hashtable;
  26. import javax.swing.JOptionPane;
  27. import javax.swing.SwingUtilities;
  28. import java.awt.*;
  29. import java.util.Collections;
  30. import java.util.Vector;
  31. import org.gjt.sp.jedit.gui.ErrorListDialog;
  32. import org.gjt.sp.jedit.msg.VFSUpdate;
  33. import org.gjt.sp.jedit.*;
  34. import org.gjt.sp.util.Log;
  35. import org.gjt.sp.util.WorkThreadPool;
  36. //}}}
  37. /**
  38. * jEdit's virtual filesystem allows it to transparently edit files
  39. * stored elsewhere than the local filesystem, for example on an FTP
  40. * site. See the {@link VFS} class for implementation details.
  41. *
  42. * @author Slava Pestov
  43. * @version $Id: VFSManager.java 4697 2003-05-10 02:47:59Z spestov $
  44. */
  45. public class VFSManager
  46. {
  47. /**
  48. * The service type. See {@link org.gjt.sp.jedit.ServiceManager}.
  49. * @since jEdit 4.2pre1
  50. */
  51. public static final String SERVICE = "org.gjt.sp.jedit.io.VFS";
  52. //{{{ init() method
  53. /**
  54. * Do not call.
  55. */
  56. public static void init()
  57. {
  58. int count = jEdit.getIntegerProperty("ioThreadCount",4);
  59. ioThreadPool = new WorkThreadPool("jEdit I/O",count);
  60. } //}}}
  61. //{{{ start() method
  62. /**
  63. * Do not call.
  64. */
  65. public static void start()
  66. {
  67. ioThreadPool.start();
  68. } //}}}
  69. //{{{ VFS methods
  70. //{{{ getFileVFS() method
  71. /**
  72. * Returns the local filesystem VFS.
  73. * @since jEdit 2.5pre1
  74. */
  75. public static VFS getFileVFS()
  76. {
  77. return fileVFS;
  78. } //}}}
  79. //{{{ getUrlVFS() method
  80. /**
  81. * Returns the URL VFS.
  82. * @since jEdit 2.5pre1
  83. */
  84. public static VFS getUrlVFS()
  85. {
  86. return urlVFS;
  87. } //}}}
  88. //{{{ getVFSByName() method
  89. /**
  90. * @deprecated Use <code>getVFSForProtocol()</code> instead.
  91. */
  92. public static VFS getVFSByName(String name)
  93. {
  94. // in new api, protocol always equals name
  95. VFS vfs = (VFS)ServiceManager.getService(SERVICE,name);
  96. if(vfs == null)
  97. return (VFS)vfsHash.get(name);
  98. else
  99. return vfs;
  100. } //}}}
  101. //{{{ getVFSForProtocol() method
  102. /**
  103. * Returns the VFS for the specified protocol.
  104. * @param protocol The protocol
  105. * @since jEdit 2.5pre1
  106. */
  107. public static VFS getVFSForProtocol(String protocol)
  108. {
  109. if(protocol.equals("file"))
  110. return fileVFS;
  111. else
  112. {
  113. VFS vfs = (VFS)ServiceManager.getService(SERVICE,protocol);
  114. if(vfs == null)
  115. vfs = (VFS)protocolHash.get(protocol);
  116. if(vfs != null)
  117. return vfs;
  118. else
  119. return urlVFS;
  120. }
  121. } //}}}
  122. //{{{ getVFSForPath() method
  123. /**
  124. * Returns the VFS for the specified path.
  125. * @param path The path
  126. * @since jEdit 2.6pre4
  127. */
  128. public static VFS getVFSForPath(String path)
  129. {
  130. if(MiscUtilities.isURL(path))
  131. return getVFSForProtocol(MiscUtilities.getProtocolOfURL(path));
  132. else
  133. return fileVFS;
  134. } //}}}
  135. //{{{ registerVFS() method
  136. /**
  137. * @deprecated Write a <code>services.xml</code> file instead;
  138. * see {@link org.gjt.sp.jedit.ServiceManager}.
  139. */
  140. public static void registerVFS(String protocol, VFS vfs)
  141. {
  142. Log.log(Log.DEBUG,VFSManager.class,"Registered "
  143. + vfs.getName() + " filesystem for "
  144. + protocol + " protocol");
  145. vfsHash.put(vfs.getName(),vfs);
  146. protocolHash.put(protocol,vfs);
  147. } //}}}
  148. //{{{ getFilesystems() method
  149. /**
  150. * @deprecated Use <code>getVFSs()</code> instead.
  151. */
  152. public static Enumeration getFilesystems()
  153. {
  154. return vfsHash.elements();
  155. } //}}}
  156. //{{{ getVFSs() method
  157. /**
  158. * Returns a list of all registered filesystems.
  159. * @since jEdit 4.2pre1
  160. */
  161. public static String[] getVFSs()
  162. {
  163. // the sooner ppl move to the new api, the less we'll need
  164. // crap like this
  165. Vector returnValue = new Vector();
  166. String[] newAPI = ServiceManager.getServiceNames(SERVICE);
  167. if(newAPI != null)
  168. {
  169. for(int i = 0; i < newAPI.length; i++)
  170. {
  171. returnValue.add(newAPI[i]);
  172. }
  173. }
  174. Enumeration oldAPI = vfsHash.keys();
  175. while(oldAPI.hasMoreElements())
  176. returnValue.add(oldAPI.nextElement());
  177. return (String[])returnValue.toArray(new String[
  178. returnValue.size()]);
  179. } //}}}
  180. //}}}
  181. //{{{ I/O request methods
  182. //{{{ getIOThreadPool() method
  183. /**
  184. * Returns the I/O thread pool.
  185. */
  186. public static WorkThreadPool getIOThreadPool()
  187. {
  188. return ioThreadPool;
  189. } //}}}
  190. //{{{ waitForRequests() method
  191. /**
  192. * Returns when all pending requests are complete.
  193. * @since jEdit 2.5pre1
  194. */
  195. public static void waitForRequests()
  196. {
  197. ioThreadPool.waitForRequests();
  198. } //}}}
  199. //{{{ errorOccurred() method
  200. /**
  201. * Returns if the last request caused an error.
  202. */
  203. public static boolean errorOccurred()
  204. {
  205. return error;
  206. } //}}}
  207. //{{{ getRequestCount() method
  208. /**
  209. * Returns the number of pending I/O requests.
  210. */
  211. public static int getRequestCount()
  212. {
  213. return ioThreadPool.getRequestCount();
  214. } //}}}
  215. //{{{ runInAWTThread() method
  216. /**
  217. * Executes the specified runnable in the AWT thread once all
  218. * pending I/O requests are complete.
  219. * @since jEdit 2.5pre1
  220. */
  221. public static void runInAWTThread(Runnable run)
  222. {
  223. ioThreadPool.addWorkRequest(run,true);
  224. } //}}}
  225. //{{{ runInWorkThread() method
  226. /**
  227. * Executes the specified runnable in one of the I/O threads.
  228. * @since jEdit 2.6pre2
  229. */
  230. public static void runInWorkThread(Runnable run)
  231. {
  232. ioThreadPool.addWorkRequest(run,false);
  233. } //}}}
  234. //}}}
  235. //{{{ error() method
  236. /**
  237. * @deprecated Call the other <code>error()</code> method instead.
  238. */
  239. public static void error(final Component comp, final String error, final Object[] args)
  240. {
  241. // if we are already in the AWT thread, take a shortcut
  242. if(SwingUtilities.isEventDispatchThread())
  243. {
  244. GUIUtilities.error(comp,error,args);
  245. return;
  246. }
  247. // the 'error' chicanery ensures that stuff like:
  248. // VFSManager.waitForRequests()
  249. // if(VFSManager.errorOccurred())
  250. // ...
  251. // will work (because the below runnable will only be
  252. // executed in the next event)
  253. VFSManager.error = true;
  254. runInAWTThread(new Runnable()
  255. {
  256. public void run()
  257. {
  258. VFSManager.error = false;
  259. if(comp == null || !comp.isShowing())
  260. GUIUtilities.error(null,error,args);
  261. else
  262. GUIUtilities.error(comp,error,args);
  263. }
  264. });
  265. } //}}}
  266. //{{{ error() method
  267. /**
  268. * Reports an I/O error.
  269. *
  270. * @param comp The component
  271. * @param path The path name that caused the error
  272. * @param message The error message property name
  273. * @param args Positional parameters
  274. * @since jEdit 4.0pre3
  275. */
  276. public static void error(Component comp,
  277. final String path,
  278. String messageProp,
  279. Object[] args)
  280. {
  281. final Frame frame = JOptionPane.getFrameForComponent(comp);
  282. synchronized(errorLock)
  283. {
  284. error = true;
  285. errors.addElement(new ErrorListDialog.ErrorEntry(
  286. path,messageProp,args));
  287. if(errors.size() == 1)
  288. {
  289. VFSManager.runInAWTThread(new Runnable()
  290. {
  291. public void run()
  292. {
  293. String caption = jEdit.getProperty(
  294. "ioerror.caption" + (errors.size() == 1
  295. ? "-1" : ""),new Integer[] {
  296. new Integer(errors.size()) });
  297. new ErrorListDialog(
  298. frame.isShowing()
  299. ? frame
  300. : jEdit.getFirstView(),
  301. jEdit.getProperty("ioerror.title"),
  302. caption,errors,false);
  303. errors.removeAllElements();
  304. error = false;
  305. }
  306. });
  307. }
  308. }
  309. } //}}}
  310. //{{{ sendVFSUpdate() method
  311. /**
  312. * Sends a VFS update message.
  313. * @param vfs The VFS
  314. * @param path The path that changed
  315. * @param parent True if an update should be sent for the path's
  316. * parent too
  317. * @since jEdit 2.6pre4
  318. */
  319. public static void sendVFSUpdate(VFS vfs, String path, boolean parent)
  320. {
  321. if(parent)
  322. {
  323. sendVFSUpdate(vfs,vfs.getParentOfPath(path),false);
  324. sendVFSUpdate(vfs,path,false);
  325. }
  326. else
  327. {
  328. // have to do this hack until VFSPath class is written
  329. if(path.length() != 1 && (path.endsWith("/")
  330. || path.endsWith(java.io.File.separator)))
  331. path = path.substring(0,path.length() - 1);
  332. synchronized(vfsUpdateLock)
  333. {
  334. for(int i = 0; i < vfsUpdates.size(); i++)
  335. {
  336. VFSUpdate msg = (VFSUpdate)vfsUpdates
  337. .elementAt(i);
  338. if(msg.getPath().equals(path))
  339. {
  340. // don't send two updates
  341. // for the same path
  342. return;
  343. }
  344. }
  345. vfsUpdates.addElement(new VFSUpdate(path));
  346. if(vfsUpdates.size() == 1)
  347. {
  348. // we were the first to add an update;
  349. // add update sending runnable to AWT
  350. // thread
  351. VFSManager.runInAWTThread(new SendVFSUpdatesSafely());
  352. }
  353. }
  354. }
  355. } //}}}
  356. //{{{ SendVFSUpdatesSafely class
  357. static class SendVFSUpdatesSafely implements Runnable
  358. {
  359. public void run()
  360. {
  361. synchronized(vfsUpdateLock)
  362. {
  363. // the vfs browser has what you might call
  364. // a design flaw, it doesn't update properly
  365. // unless the vfs update for a parent arrives
  366. // before any updates for the children. sorting
  367. // the list alphanumerically guarantees this.
  368. Collections.sort(vfsUpdates,
  369. new MiscUtilities.StringCompare()
  370. );
  371. for(int i = 0; i < vfsUpdates.size(); i++)
  372. {
  373. EditBus.send((VFSUpdate)vfsUpdates.elementAt(i));
  374. }
  375. vfsUpdates.removeAllElements();
  376. }
  377. }
  378. } //}}}
  379. //{{{ Private members
  380. //{{{ Static variables
  381. private static WorkThreadPool ioThreadPool;
  382. private static VFS fileVFS;
  383. private static VFS urlVFS;
  384. private static Hashtable vfsHash;
  385. private static Hashtable protocolHash;
  386. private static boolean error;
  387. private static Object errorLock;
  388. private static Vector errors;
  389. private static Object vfsUpdateLock;
  390. private static Vector vfsUpdates;
  391. //}}}
  392. //{{{ Class initializer
  393. static
  394. {
  395. errorLock = new Object();
  396. errors = new Vector();
  397. fileVFS = new FileVFS();
  398. urlVFS = new UrlVFS();
  399. vfsHash = new Hashtable();
  400. protocolHash = new Hashtable();
  401. vfsUpdateLock = new Object();
  402. vfsUpdates = new Vector();
  403. } //}}}
  404. private VFSManager() {}
  405. //}}}
  406. }