KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > filesystem > provider > FileStore


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.filesystem.provider;
12
13 import java.io.*;
14 import java.net.URI JavaDoc;
15 import org.eclipse.core.filesystem.*;
16 import org.eclipse.core.internal.filesystem.*;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.osgi.util.NLS;
19
20 /**
21  * The abstract superclass of all {@link IFileStore} implementations. All
22  * file stores must subclass this base class, implementing all abstract
23  * methods according to their specification in the {@link IFileStore} API.
24  * <p>
25  * Clients may subclass this class.
26  * </p>
27  * @since org.eclipse.core.filesystem 1.0
28  */

29 public abstract class FileStore extends PlatformObject implements IFileStore {
30     /**
31      * Singleton buffer created to avoid buffer creations in the
32      * transferStreams method. Used as an optimization, based on the assumption
33      * that multiple writes won't happen in a given instance of FileStore.
34      */

35     private static final byte[] buffer = new byte[8192];
36
37     /**
38      * A file info array of size zero that can be used as a return value for methods
39      * that return IFileInfo[] to avoid creating garbage objects.
40      */

41     protected static final IFileInfo[] EMPTY_FILE_INFO_ARRAY = new IFileInfo[0];
42
43     /**
44      * A string array of size zero that can be used as a return value for methods
45      * that return String[] to avoid creating garbage objects.
46      */

47     protected static final String JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
48
49     /**
50      * Transfers the contents of an input stream to an output stream, using a large
51      * buffer.
52      *
53      * @param source The input stream to transfer
54      * @param destination The destination stream of the transfer
55      * @param path A path representing the data being transferred for use in error
56      * messages.
57      * @param monitor A progress monitor. The monitor is assumed to have
58      * already done beginWork with one unit of work allocated per buffer load
59      * of contents to be transferred.
60      * @throws CoreException
61      */

62     private static final void transferStreams(InputStream source, OutputStream destination, String JavaDoc path, IProgressMonitor monitor) throws CoreException {
63         monitor = Policy.monitorFor(monitor);
64         try {
65             /*
66              * Note: although synchronizing on the buffer is thread-safe,
67              * it may result in slower performance in the future if we want
68              * to allow concurrent writes.
69              */

70             synchronized (buffer) {
71                 while (true) {
72                     int bytesRead = -1;
73                     try {
74                         bytesRead = source.read(buffer);
75                     } catch (IOException e) {
76                         String JavaDoc msg = NLS.bind(Messages.failedReadDuringWrite, path);
77                         Policy.error(EFS.ERROR_READ, msg, e);
78                     }
79                     if (bytesRead == -1)
80                         break;
81                     try {
82                         destination.write(buffer, 0, bytesRead);
83                     } catch (IOException e) {
84                         String JavaDoc msg = NLS.bind(Messages.couldNotWrite, path);
85                         Policy.error(EFS.ERROR_WRITE, msg, e);
86                     }
87                     monitor.worked(1);
88                 }
89             }
90         } finally {
91             Policy.safeClose(source);
92             Policy.safeClose(destination);
93         }
94     }
95
96     /**
97      * The default implementation of {@link IFileStore#childInfos(int, IProgressMonitor)}.
98      * Subclasses should override this method where a more efficient implementation
99      * is possible. This default implementation calls {@link #fetchInfo()} on each
100      * child, which will result in a file system call for each child.
101      */

102     public IFileInfo[] childInfos(int options, IProgressMonitor monitor) throws CoreException {
103         IFileStore[] childStores = childStores(options, monitor);
104         IFileInfo[] childInfos = new IFileInfo[childStores.length];
105         for (int i = 0; i < childStores.length; i++) {
106             childInfos[i] = childStores[i].fetchInfo();
107         }
108         return childInfos;
109     }
110
111     /* (non-Javadoc)
112      * @see org.eclipse.core.filesystem.IFileStore#childNames(int, org.eclipse.core.runtime.IProgressMonitor)
113      */

114     public abstract String JavaDoc[] childNames(int options, IProgressMonitor monitor) throws CoreException;
115
116     /**
117      * The default implementation of {@link IFileStore#childStores(int, IProgressMonitor)}.
118      * Subclasses may override.
119      */

120     public IFileStore[] childStores(int options, IProgressMonitor monitor) throws CoreException {
121         String JavaDoc[] children = childNames(options, monitor);
122         IFileStore[] wrapped = new IFileStore[children.length];
123         for (int i = 0; i < wrapped.length; i++)
124             wrapped[i] = getChild(children[i]);
125         return wrapped;
126     }
127
128     /**
129      * The default implementation of {@link IFileStore#copy(IFileStore, int, IProgressMonitor)}.
130      * This implementation performs a copy by using other primitive methods.
131      * Subclasses may override this method.
132      */

133     public void copy(IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
134         monitor = Policy.monitorFor(monitor);
135         Policy.checkCanceled(monitor);
136         final IFileInfo sourceInfo = fetchInfo(EFS.NONE, null);
137         if (sourceInfo.isDirectory())
138             copyDirectory(sourceInfo, destination, options, monitor);
139         else
140             copyFile(sourceInfo, destination, options, monitor);
141     }
142
143     /**
144      * Recursively copies a directory as specified by
145      * {@link IFileStore#copy(IFileStore, int, IProgressMonitor)}.
146      *
147      * @param sourceInfo The current file information for the source of the move
148      * @param destination The destination of the copy.
149      * @param options bit-wise or of option flag constants (
150      * {@link EFS#OVERWRITE} or {@link EFS#SHALLOW}).
151      * @param monitor a progress monitor, or <code>null</code> if progress
152      * reporting and cancellation are not desired
153      * @exception CoreException if this method fails. Reasons include:
154      * <ul>
155      * <li> This store does not exist.</li>
156      * <li> The <code>OVERWRITE</code> flag is not specified and a file of the
157      * same name already exists at the copy destination.</li>
158      * </ul>
159      */

160     protected void copyDirectory(IFileInfo sourceInfo, IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
161         try {
162             IFileStore[] children = null;
163             int opWork = 1;
164             if ((options & EFS.SHALLOW) == 0) {
165                 children = childStores(EFS.NONE, null);
166                 opWork += children.length;
167             }
168             monitor.beginTask("", opWork); //$NON-NLS-1$
169
monitor.subTask(NLS.bind(Messages.copying, toString()));
170             // create directory
171
destination.mkdir(EFS.NONE, Policy.subMonitorFor(monitor, 1));
172
173             if (children == null)
174                 return;
175             // copy children
176
for (int i = 0; i < children.length; i++)
177                 children[i].copy(destination.getChild(children[i].getName()), options, Policy.subMonitorFor(monitor, 1));
178         } finally {
179             monitor.done();
180         }
181     }
182
183     /**
184      * Copies a file as specified by
185      * {@link IFileStore#copy(IFileStore, int, IProgressMonitor)}.
186
187      * @param sourceInfo The current file information for the source of the move
188      * @param destination The destination of the copy.
189      * @param options bit-wise or of option flag constants (
190      * {@link EFS#OVERWRITE} or {@link EFS#SHALLOW}).
191      * @param monitor a progress monitor, or <code>null</code> if progress
192      * reporting and cancellation are not desired
193      * @exception CoreException if this method fails. Reasons include:
194      * <ul>
195      * <li> This store does not exist.</li>
196      * <li> The <code>OVERWRITE</code> flag is not specified and a file of the
197      * same name already exists at the copy destination.</li>
198      * </ul>
199      */

200     protected void copyFile(IFileInfo sourceInfo, IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
201         try {
202             if ((options & EFS.OVERWRITE) == 0 && destination.fetchInfo().exists())
203                 Policy.error(EFS.ERROR_EXISTS, NLS.bind(Messages.fileExists, destination));
204             long length = sourceInfo.getLength();
205             int totalWork;
206             if (length == -1)
207                 totalWork = IProgressMonitor.UNKNOWN;
208             else
209                 totalWork = 1 + (int) (length / buffer.length);
210             String JavaDoc sourcePath = toString();
211             monitor.beginTask(NLS.bind(Messages.copying, sourcePath), totalWork);
212             InputStream in = null;
213             OutputStream out = null;
214             try {
215                 in = openInputStream(EFS.NONE, Policy.subMonitorFor(monitor, 0));
216                 out = destination.openOutputStream(EFS.NONE, Policy.subMonitorFor(monitor, 0));
217                 transferStreams(in, out, sourcePath, monitor);
218                 transferAttributes(sourceInfo, destination);
219             } catch (CoreException e) {
220                 Policy.safeClose(in);
221                 Policy.safeClose(out);
222                 //if we failed to write, try to cleanup the half written file
223
if (!destination.fetchInfo(0, null).exists())
224                     destination.delete(EFS.NONE, null);
225                 throw e;
226             }
227         } finally {
228             monitor.done();
229         }
230     }
231
232     /**
233      * The default implementation of {@link IFileStore#delete(int, IProgressMonitor)}.
234      * This implementation always throws an exception indicating that deletion
235      * is not supported by this file system. This method should be overridden
236      * for all file systems on which deletion is supported.
237      *
238      * @param options bit-wise or of option flag constants
239      * @param monitor a progress monitor, or <code>null</code> if progress
240      * reporting and cancellation are not desired
241      */

242     public void delete(int options, IProgressMonitor monitor) throws CoreException {
243         Policy.error(EFS.ERROR_DELETE, NLS.bind(Messages.noImplDelete, toString()));
244     }
245
246     /**
247      * This implementation of {@link Object#equals(Object)} defines
248      * equality based on the file store's URI. Subclasses should override
249      * this method to return <code>true</code> if and only if the two file stores
250      * represent the same resource in the backing file system. Issues to watch
251      * out for include whether the file system is case-sensitive, and whether trailing
252      * slashes are considered significant. Subclasses that override this method
253      * should also override {@link #hashCode()}.
254      *
255      * @param obj The object to compare with the receiver for equality
256      * @return <code>true</code> if this object is equal to the provided object,
257      * and <code>false</code> otherwise.
258      * @since org.eclipse.core.filesystem 1.1
259      */

260     public boolean equals(Object JavaDoc obj) {
261         if (this == obj)
262             return true;
263         if (!(obj instanceof FileStore))
264             return false;
265         return toURI().equals(((FileStore) obj).toURI());
266     }
267
268     /**
269      * The default implementation of {@link IFileStore#fetchInfo()}.
270      * This implementation forwards to {@link IFileStore#fetchInfo(int, IProgressMonitor)}.
271      * Subclasses may override this method.
272      */

273     public IFileInfo fetchInfo() {
274         try {
275             return fetchInfo(EFS.NONE, null);
276         } catch (CoreException e) {
277             //there was an error contacting the file system, so treat it as non-existent file
278
FileInfo result = new FileInfo(getName());
279             result.setExists(false);
280             return result;
281         }
282     }
283
284     /* (non-Javadoc)
285      * @see org.eclipse.core.filesystem.IFileStore#fetchInfo(int, org.eclipse.core.runtime.IProgressMonitor)
286      */

287     public abstract IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException;
288
289     /**
290      * The default implementation of {@link IFileStore#getChild(IPath)}.
291      * Subclasses may override.
292      */

293     public IFileStore getChild(IPath path) {
294         IFileStore result = this;
295         for (int i = 0, imax = path.segmentCount(); i < imax; i++)
296             result = result.getChild(path.segment(i));
297         return result;
298     }
299
300     /* (non-Javadoc)
301      * @see org.eclipse.core.filesystem.IFileStore#getChild(java.lang.String)
302      */

303     public abstract IFileStore getChild(String JavaDoc name);
304
305     /**
306      * The default implementation of {@link IFileStore#getFileSystem()}.
307      * Subclasses may override.
308      */

309     public IFileSystem getFileSystem() {
310         try {
311             return EFS.getFileSystem(toURI().getScheme());
312         } catch (CoreException e) {
313             //this will only happen if toURI() has been incorrectly implemented
314
throw new RuntimeException JavaDoc(e);
315         }
316     }
317
318     /* (non-Javadoc)
319      * @see org.eclipse.core.filesystem.IFileStore#getName()
320      */

321     public abstract String JavaDoc getName();
322
323     /* (non-Javadoc)
324      * @see org.eclipse.core.filesystem.IFileStore#getParent()
325      */

326     public abstract IFileStore getParent();
327
328     /**
329      * This implementation of {@link Object#hashCode()} uses a definition
330      * of equality based on equality of the file store's URI. Subclasses that
331      * override {@link #equals(Object)} should also override this method
332      * to ensure the contract of {@link Object#hashCode()} is honored.
333      *
334      * @return A hash code value for this file store
335      * @since org.eclipse.core.filesystem 1.1
336      */

337     public int hashCode() {
338         return toURI().hashCode();
339     }
340
341     /**
342      * The default implementation of {@link IFileStore#isParentOf(IFileStore)}.
343      * This implementation performs parent calculation using other primitive methods.
344      * Subclasses may override this method.
345      *
346      * @param other The store to test for parentage.
347      * @return <code>true</code> if this store is a parent of the provided
348      * store, and <code>false</code> otherwise.
349      */

350     public boolean isParentOf(IFileStore other) {
351         while (true) {
352             other = other.getParent();
353             if (other == null)
354                 return false;
355             if (this.equals(other))
356                 return true;
357         }
358     }
359
360     /**
361      * The default implementation of {@link IFileStore#mkdir(int, IProgressMonitor)}.
362      * This implementation always throws an exception indicating that this file system
363      * is read only. This method should be overridden for all writable file systems.
364      *
365      * @param options bit-wise or of option flag constants
366      * @param monitor a progress monitor, or <code>null</code> if progress
367      * reporting and cancellation are not desired
368      */

369     public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException {
370         Policy.error(EFS.ERROR_WRITE, NLS.bind(Messages.noImplWrite, toString()));
371         return null;//can't get here
372
}
373
374     /**
375      * The default implementation of {@link IFileStore#move(IFileStore, int, IProgressMonitor)}.
376      * This implementation performs a move by using other primitive methods.
377      * Subclasses may override this method.
378      */

379     public void move(IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
380         monitor = Policy.monitorFor(monitor);
381         try {
382             monitor.beginTask(NLS.bind(Messages.moving, destination.toString()), 100);
383             copy(destination, options & EFS.OVERWRITE, Policy.subMonitorFor(monitor, 70));
384             delete(EFS.NONE, Policy.subMonitorFor(monitor, 30));
385         } catch (CoreException e) {
386             //throw new error to indicate failure occurred during a move
387
String JavaDoc message = NLS.bind(Messages.couldNotMove, toString());
388             Policy.error(EFS.ERROR_WRITE, message, e);
389         } finally {
390             monitor.done();
391         }
392     }
393
394     /* (non-Javadoc)
395      * @see org.eclipse.core.filesystem.IFileStore#openInputStream(int, IProgressMonitor)
396      */

397     public abstract InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException;
398
399     /**
400      * The default implementation of {@link IFileStore#openOutputStream(int, IProgressMonitor)}.
401      * This implementation always throws an exception indicating that this file system
402      * is read only. This method should be overridden for all writable file systems.
403      *
404      * @param options bit-wise or of option flag constants
405      * @param monitor a progress monitor, or <code>null</code> if progress
406      * reporting and cancellation are not desired
407      */

408     public OutputStream openOutputStream(int options, IProgressMonitor monitor) throws CoreException {
409         Policy.error(EFS.ERROR_WRITE, NLS.bind(Messages.noImplWrite, toString()));
410         return null;//can't get here
411
}
412
413     /**
414      * The default implementation of {@link IFileStore#putInfo(IFileInfo, int, IProgressMonitor)}.
415      * This implementation always throws an exception indicating that this file system
416      * is read only. This method should be overridden for all writable file systems.
417      *
418      * @param options bit-wise or of option flag constants
419      * @param monitor a progress monitor, or <code>null</code> if progress
420      * reporting and cancellation are not desired
421      */

422     public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) throws CoreException {
423         Policy.error(EFS.ERROR_WRITE, NLS.bind(Messages.noImplWrite, toString()));
424     }
425
426     /**
427      * The default implementation of {@link IFileStore#toLocalFile(int, IProgressMonitor)}.
428      * When the {@link EFS#CACHE} option is specified, this method returns
429      * a cached copy of this store in the local file system, or <code>null</code> if
430      * this store does not exist.
431      */

432     public java.io.File JavaDoc toLocalFile(int options, IProgressMonitor monitor) throws CoreException {
433         monitor = Policy.monitorFor(monitor);
434         //caching is the only recognized option
435
if (options != EFS.CACHE)
436             return null;
437         return FileCache.getCache().cache(this, monitor);
438     }
439
440     /**
441      * Default implementation of {@link IFileStore#toString()}. This default implementation
442      * returns a string equal to the one returned by #toURI().toString(). Subclasses
443      * may override to provide a more specific string representation of this store.
444      *
445      * @return A string representation of this store.
446      */

447     public String JavaDoc toString() {
448         return toURI().toString();
449     }
450
451     /* (non-Javadoc)
452      * @see org.eclipse.core.filesystem.IFileStore#toURI()
453      */

454     public abstract URI JavaDoc toURI();
455
456     private void transferAttributes(IFileInfo sourceInfo, IFileStore destination) throws CoreException {
457         int options = EFS.SET_ATTRIBUTES | EFS.SET_LAST_MODIFIED;
458         destination.putInfo(sourceInfo, options, null);
459     }
460 }
Popular Tags