KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > filebuffers > ResourceFileBuffer


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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.internal.filebuffers;
12
13 import java.net.URI JavaDoc;
14
15 import org.eclipse.core.filesystem.EFS;
16 import org.eclipse.core.filesystem.IFileInfo;
17
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.core.runtime.ILog;
20 import org.eclipse.core.runtime.IPath;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.IStatus;
23 import org.eclipse.core.runtime.MultiStatus;
24 import org.eclipse.core.runtime.OperationCanceledException;
25 import org.eclipse.core.runtime.Status;
26 import org.eclipse.core.runtime.SubProgressMonitor;
27 import org.eclipse.core.runtime.jobs.ISchedulingRule;
28
29 import org.eclipse.core.resources.IFile;
30 import org.eclipse.core.resources.IResource;
31 import org.eclipse.core.resources.IResourceChangeEvent;
32 import org.eclipse.core.resources.IResourceChangeListener;
33 import org.eclipse.core.resources.IResourceDelta;
34 import org.eclipse.core.resources.IResourceRuleFactory;
35 import org.eclipse.core.resources.IWorkspace;
36 import org.eclipse.core.resources.IWorkspaceRoot;
37 import org.eclipse.core.resources.ResourcesPlugin;
38
39 import org.eclipse.core.filebuffers.IFileBufferStatusCodes;
40
41 import org.eclipse.jface.text.IDocumentExtension4;
42
43
44 public abstract class ResourceFileBuffer extends AbstractFileBuffer {
45
46         /**
47          * Runnable encapsulating an element state change. This runnable ensures
48          * that a element change failed message is sent out to the element state
49          * listeners in case an exception occurred.
50          */

51         private class SafeFileChange implements Runnable JavaDoc {
52
53             /**
54              * Creates a new safe runnable for the given file.
55              */

56             public SafeFileChange() {
57             }
58
59             /**
60              * Execute the change.
61              * Subclass responsibility.
62              *
63              * @exception Exception in case of error
64              */

65             protected void execute() throws Exception JavaDoc {
66             }
67
68             /**
69              * Does everything necessary prior to execution.
70              */

71             public void preRun() {
72                 fManager.fireStateChanging(ResourceFileBuffer.this);
73             }
74
75             /*
76              * @see java.lang.Runnable#run()
77              */

78             public void run() {
79
80                 if (isDisconnected()) {
81                     fManager.fireStateChangeFailed(ResourceFileBuffer.this);
82                     return;
83                 }
84
85                 try {
86                     execute();
87                 } catch (Exception JavaDoc x) {
88                     FileBuffersPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, "Exception when synchronizing", x)); //$NON-NLS-1$
89
fManager.fireStateChangeFailed(ResourceFileBuffer.this);
90                 }
91             }
92         }
93
94         /**
95          * Synchronizes the document with external resource changes.
96          */

97         private class FileSynchronizer implements IResourceChangeListener {
98
99             /** A flag indicating whether this synchronizer is installed or not. */
100             private boolean fIsInstalled= false;
101
102             /**
103              * Creates a new file synchronizer. Is not yet installed on a file.
104              */

105             public FileSynchronizer() {
106             }
107
108             /**
109              * Installs the synchronizer on the file.
110              */

111             public void install() {
112                 fFile.getWorkspace().addResourceChangeListener(this);
113                 fIsInstalled= true;
114             }
115
116             /**
117              * Uninstalls the synchronizer from the file.
118              */

119             public void uninstall() {
120                 fFile.getWorkspace().removeResourceChangeListener(this);
121                 fIsInstalled= false;
122             }
123
124             /*
125              * @see IResourceChangeListener#resourceChanged(IResourceChangeEvent)
126              */

127             public void resourceChanged(IResourceChangeEvent e) {
128                 IResourceDelta delta= e.getDelta();
129                 if (delta != null)
130                     delta= delta.findMember(fFile.getFullPath());
131
132                 if (delta != null && fIsInstalled) {
133                     SafeFileChange fileChange= null;
134
135                     final int flags= delta.getFlags();
136                     switch (delta.getKind()) {
137                         case IResourceDelta.CHANGED:
138                             if ((IResourceDelta.ENCODING & flags) != 0) {
139                                 if (!isDisconnected() && !fCanBeSaved && isSynchronized()) {
140                                     fileChange= new SafeFileChange() {
141                                         protected void execute() throws Exception JavaDoc {
142                                             handleFileContentChanged(false);
143                                         }
144                                     };
145                                 }
146                             }
147                             if (fileChange == null && (IResourceDelta.CONTENT & flags) != 0) {
148                                 if (!isDisconnected() && !fCanBeSaved && (!isSynchronized() || (IResourceDelta.REPLACED & flags) != 0)) {
149                                     fileChange= new SafeFileChange() {
150                                         protected void execute() throws Exception JavaDoc {
151                                             handleFileContentChanged(false);
152                                         }
153                                     };
154                                 }
155                             }
156                             break;
157                         case IResourceDelta.REMOVED:
158                             if ((IResourceDelta.MOVED_TO & flags) != 0) {
159                                 final IPath path= delta.getMovedToPath();
160                                 fileChange= new SafeFileChange() {
161                                     protected void execute() throws Exception JavaDoc {
162                                         handleFileMoved(path);
163                                     }
164                                 };
165                             } else {
166                                 if (!isDisconnected() && !fCanBeSaved) {
167                                     fileChange= new SafeFileChange() {
168                                         protected void execute() throws Exception JavaDoc {
169                                             handleFileDeleted();
170                                         }
171                                     };
172                                 }
173                             }
174                             break;
175                     }
176
177                     if (fileChange != null) {
178                         fileChange.preRun();
179                         fManager.execute(fileChange, isSynchronizationContextRequested());
180                     }
181                 }
182             }
183         }
184
185
186
187     /** The location */
188     protected IPath fLocation;
189     /** The element for which the info is stored */
190     protected IFile fFile;
191     /** How often the element has been connected */
192     protected int fReferenceCount;
193     /** Can the element be saved */
194     protected boolean fCanBeSaved= false;
195     /** Has element state been validated */
196     protected boolean fIsStateValidated= false;
197     /** The status of this element */
198     protected IStatus fStatus;
199     /** The file synchronizer. */
200     protected FileSynchronizer fFileSynchronizer;
201     /** The modification stamp at which this buffer synchronized with the underlying file. */
202     protected long fSynchronizationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
203     /** How often the synchronization context has been requested */
204     protected int fSynchronizationContextCount;
205     /** The text file buffer manager */
206     protected ResourceTextFileBufferManager fManager;
207
208     
209     public ResourceFileBuffer(ResourceTextFileBufferManager manager) {
210         super();
211         fManager= manager;
212     }
213
214
215     abstract protected void addFileBufferContentListeners();
216
217     abstract protected void removeFileBufferContentListeners();
218
219     abstract protected void initializeFileBufferContent(IProgressMonitor monitor) throws CoreException;
220
221     abstract protected void commitFileBufferContent(IProgressMonitor monitor, boolean overwrite) throws CoreException;
222
223     abstract protected void handleFileContentChanged(boolean revert) throws CoreException;
224
225
226     public void create(IPath location, IProgressMonitor monitor) throws CoreException {
227         monitor= Progress.getMonitor(monitor);
228         monitor.beginTask(FileBuffersMessages.ResourceFileBuffer_task_creatingFileBuffer, 2);
229
230         try {
231             IWorkspaceRoot workspaceRoot= ResourcesPlugin.getWorkspace().getRoot();
232             IFile file= workspaceRoot.getFile(location);
233             if (file == null)
234                 throw new CoreException(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, FileBuffersMessages.ResourceFileBuffer_error_fileDoesNotExist, null));
235             URI JavaDoc uri= file.getLocationURI();
236             if (uri == null)
237                 throw new CoreException(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, FileBuffersMessages.ResourceFileBuffer_error_fileDoesNotExist, null));
238
239             fLocation= location;
240             fFile= file;
241             fFileStore= EFS.getStore(uri);
242             fFileSynchronizer= new FileSynchronizer();
243
244             SubProgressMonitor subMonitor= new SubProgressMonitor(monitor, 1);
245             initializeFileBufferContent(subMonitor);
246             subMonitor.done();
247
248             fSynchronizationStamp= fFile.getModificationStamp();
249
250             addFileBufferContentListeners();
251
252         } finally {
253             monitor.done();
254         }
255     }
256
257     public void connect() {
258         ++fReferenceCount;
259         if (fReferenceCount == 1)
260             connected();
261     }
262
263     /**
264      * Called when this file buffer has been connected. This is the case when
265      * there is exactly one connection.
266      * <p>
267      * Clients may extend this method.
268      */

269     protected void connected() {
270         fFileSynchronizer.install();
271     }
272
273     public void disconnect() throws CoreException {
274         --fReferenceCount;
275         if (fReferenceCount <= 0)
276             disconnected();
277     }
278
279     /**
280      * Called when this file buffer has been disconnected. This is the case when
281      * the number of connections drops below <code>1</code>.
282      * <p>
283      * Clients may extend this method.
284      */

285     protected void disconnected() {
286         if (fFileSynchronizer != null) {
287             fFileSynchronizer.uninstall();
288             fFileSynchronizer= null;
289         }
290         removeFileBufferContentListeners();
291     }
292
293     /*
294      * @see org.eclipse.core.internal.filebuffers.AbstractFileBuffer#isDisconnected()
295      * @since 3.1
296      */

297     public boolean isDisconnected() {
298         return fFileSynchronizer == null;
299     }
300
301     /*
302      * @see org.eclipse.core.filebuffers.IFileBuffer#getLocation()
303      */

304     public IPath getLocation() {
305         return fLocation;
306     }
307     
308     /*
309      * @see org.eclipse.core.filebuffers.IFileBuffer#computeCommitRule()
310      */

311     public ISchedulingRule computeCommitRule() {
312         IResourceRuleFactory factory= ResourcesPlugin.getWorkspace().getRuleFactory();
313         return factory.modifyRule(fFile);
314     }
315
316     /*
317      * @see org.eclipse.core.filebuffers.IFileBuffer#commit(org.eclipse.core.runtime.IProgressMonitor, boolean)
318      */

319     public void commit(IProgressMonitor monitor, boolean overwrite) throws CoreException {
320         if (!isDisconnected() && fCanBeSaved) {
321
322             fManager.fireStateChanging(this);
323
324             try {
325                 commitFileBufferContent(monitor, overwrite);
326             } catch (CoreException x) {
327                 fManager.fireStateChangeFailed(this);
328                 throw x;
329             } catch (RuntimeException JavaDoc x) {
330                 fManager.fireStateChangeFailed(this);
331                 throw x;
332             }
333
334             fCanBeSaved= false;
335             fManager.fireDirtyStateChanged(this, fCanBeSaved);
336         }
337     }
338
339     /*
340      * @see org.eclipse.core.filebuffers.IFileBuffer#revert(org.eclipse.core.runtime.IProgressMonitor)
341      */

342     public void revert(IProgressMonitor monitor) throws CoreException {
343         if (isDisconnected())
344             return;
345
346         if (!fFile.isSynchronized(IResource.DEPTH_INFINITE)) {
347             fCanBeSaved= false;
348             refreshFile(monitor);
349             return;
350         }
351
352         try {
353             fManager.fireStateChanging(this);
354             handleFileContentChanged(true);
355         } catch (RuntimeException JavaDoc x) {
356             fManager.fireStateChangeFailed(this);
357             throw x;
358         }
359     }
360
361     /*
362      * @see org.eclipse.core.filebuffers.IFileBuffer#isDirty()
363      */

364     public boolean isDirty() {
365         return fCanBeSaved;
366     }
367
368     /*
369      * @see org.eclipse.core.filebuffers.IFileBuffer#setDirty(boolean)
370      */

371     public void setDirty(boolean isDirty) {
372         fCanBeSaved= isDirty;
373     }
374
375     /*
376      * @see org.eclipse.core.filebuffers.IFileBuffer#isShared()
377      */

378     public boolean isShared() {
379         return fReferenceCount > 1;
380     }
381
382     /*
383      * @see org.eclipse.core.filebuffers.IFileBuffer#computeValidateStateRule()
384      */

385     public ISchedulingRule computeValidateStateRule() {
386         IResourceRuleFactory factory= ResourcesPlugin.getWorkspace().getRuleFactory();
387         return factory.validateEditRule(new IResource[] { fFile });
388     }
389
390     /*
391      * @see org.eclipse.core.filebuffers.IFileBuffer#validateState(org.eclipse.core.runtime.IProgressMonitor, java.lang.Object)
392      */

393     public void validateState(IProgressMonitor monitor, Object JavaDoc computationContext) throws CoreException {
394         if (!isDisconnected() && !fIsStateValidated) {
395
396             fStatus= null;
397
398             fManager.fireStateChanging(this);
399
400             try {
401                 if (fFile.isReadOnly()) {
402                     IWorkspace workspace= fFile.getWorkspace();
403                     fStatus= workspace.validateEdit(new IFile[] { fFile }, computationContext);
404                     if (fStatus.isOK())
405                         handleFileContentChanged(false);
406                 }
407                 
408                 if (isDerived(fFile)) {
409                     IStatus status= new Status(IStatus.WARNING, FileBuffersPlugin.PLUGIN_ID, IFileBufferStatusCodes.DERIVED_FILE, FileBuffersMessages.ResourceFileBuffer_warning_fileIsDerived, null);
410                     if (fStatus == null || fStatus.isOK())
411                         fStatus= status;
412                     else
413                         fStatus= new MultiStatus(FileBuffersPlugin.PLUGIN_ID, IFileBufferStatusCodes.STATE_VALIDATION_FAILED, new IStatus[] {fStatus, status}, FileBuffersMessages.ResourceFileBuffer_stateValidationFailed, null);
414                 }
415                 
416             } catch (RuntimeException JavaDoc x) {
417                 fManager.fireStateChangeFailed(this);
418                 throw x;
419             }
420
421             fIsStateValidated= fStatus == null || fStatus.getSeverity() != IStatus.CANCEL;
422             fManager.fireStateValidationChanged(this, fIsStateValidated);
423         }
424     }
425
426     /*
427      *
428      * @see IResource#isDerived()
429      * @since 3.3
430      */

431     private boolean isDerived(IResource resource) {
432         while (resource != null) {
433             if (resource.isDerived())
434                 return true;
435             resource= resource.getParent();
436         }
437         return false;
438     }
439
440     /*
441      * @see org.eclipse.core.filebuffers.IFileBuffer#isStateValidated()
442      */

443     public boolean isStateValidated() {
444         return fIsStateValidated;
445     }
446
447     /*
448      * @see org.eclipse.core.filebuffers.IFileBuffer#resetStateValidation()
449      */

450     public void resetStateValidation() {
451         if (fIsStateValidated) {
452             fIsStateValidated= false;
453             fManager.fireStateValidationChanged(this, fIsStateValidated);
454         }
455     }
456
457     /**
458      * Sends out the notification that the file serving as document input has been moved.
459      *
460      * @param newLocation the path of the new location of the file
461      */

462     protected void handleFileMoved(IPath newLocation) {
463         fManager.fireUnderlyingFileMoved(this, newLocation);
464     }
465
466     /**
467      * Sends out the notification that the file serving as document input has been deleted.
468      */

469     protected void handleFileDeleted() {
470         fManager.fireUnderlyingFileDeleted(this);
471     }
472
473     /**
474      * Refreshes the given file.
475      *
476      * @param monitor the progress monitor
477      */

478     protected void refreshFile(IProgressMonitor monitor) {
479         try {
480             fFile.refreshLocal(IResource.DEPTH_INFINITE, monitor);
481         } catch (OperationCanceledException x) {
482         } catch (CoreException x) {
483             handleCoreException(x);
484         }
485     }
486
487     /**
488      * Defines the standard procedure to handle <code>CoreExceptions</code>. Exceptions
489      * are written to the plug-in log.
490      *
491      * @param exception the exception to be logged
492      */

493     protected void handleCoreException(CoreException exception) {
494         ILog log= FileBuffersPlugin.getDefault().getLog();
495         log.log(exception.getStatus());
496     }
497
498     /*
499      * @see org.eclipse.core.filebuffers.IFileBuffer#isSynchronized()
500      */

501     public boolean isSynchronized() {
502         if (fSynchronizationStamp == fFile.getModificationStamp() && fFile.isSynchronized(IResource.DEPTH_ZERO))
503             return true;
504         
505         fSynchronizationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
506         return false;
507     }
508
509     /*
510      * @see org.eclipse.core.filebuffers.IFileBuffer#requestSynchronizationContext()
511      */

512     public void requestSynchronizationContext() {
513         ++ fSynchronizationContextCount;
514     }
515
516     /*
517      * @see org.eclipse.core.filebuffers.IFileBuffer#releaseSynchronizationContext()
518      */

519     public void releaseSynchronizationContext() {
520         -- fSynchronizationContextCount;
521     }
522
523     /*
524      * @see org.eclipse.core.filebuffers.IFileBuffer#isSynchronizationContextRequested()
525      */

526     public boolean isSynchronizationContextRequested() {
527         return fSynchronizationContextCount > 0;
528     }
529
530     /*
531      * @see org.eclipse.core.filebuffers.IFileBuffer#isCommitable()
532      */

533     public boolean isCommitable() {
534         IFileInfo info= fFileStore.fetchInfo();
535         return info.exists() && !info.getAttribute(EFS.ATTRIBUTE_READ_ONLY);
536     }
537
538     /*
539      * @see org.eclipse.core.filebuffers.IStateValidationSupport#validationStateChanged(boolean, org.eclipse.core.runtime.IStatus)
540      */

541     public void validationStateChanged(boolean validationState, IStatus status) {
542         fIsStateValidated= validationState;
543         fStatus= status;
544     }
545 }
546
Popular Tags