~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to xml/multiview/src/org/netbeans/modules/xml/multiview/XmlMultiViewDataObject.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
 
 
42
package org.netbeans.modules.xml.multiview;
 
43
 
 
44
import org.netbeans.core.spi.multiview.MultiViewElement;
 
45
import org.openide.cookies.SaveCookie;
 
46
import org.openide.cookies.EditorCookie;
 
47
import org.openide.filesystems.FileObject;
 
48
import org.openide.filesystems.FileLock;
 
49
import org.openide.filesystems.FileAlreadyLockedException;
 
50
import org.openide.loaders.DataObjectExistsException;
 
51
import org.openide.loaders.MultiDataObject;
 
52
import org.openide.loaders.MultiFileLoader;
 
53
import org.openide.nodes.CookieSet;
 
54
import org.openide.util.Lookup;
 
55
import org.openide.windows.CloneableTopComponent;
 
56
import org.openide.ErrorManager;
 
57
import org.openide.NotifyDescriptor;
 
58
import org.openide.DialogDisplayer;
 
59
import org.openide.util.io.ReaderInputStream;
 
60
import org.openide.util.NbBundle;
 
61
 
 
62
import java.io.*;
 
63
import java.util.Enumeration;
 
64
import java.util.Date;
 
65
import java.lang.ref.WeakReference;
 
66
import org.netbeans.modules.xml.api.XmlFileEncodingQueryImpl;
 
67
import org.netbeans.spi.queries.FileEncodingQueryImplementation;
 
68
 
 
69
/**
 
70
 * Base class for data objects that are used as a basis for
 
71
 * the xml multiview. Provides support for caching data ({@link DataCache}), switching
 
72
 * view, encoding and keeping track of currently active multiview element. Furthermore, it
 
73
 * associates <code>XmlMultiViewEditorSupport</code> with this data object.
 
74
 *
 
75
 * Created on October 5, 2004, 10:49 AM
 
76
 * @author  mkuchtiak
 
77
 */
 
78
public abstract class XmlMultiViewDataObject extends MultiDataObject implements CookieSet.Factory {
 
79
    
 
80
    public static final String PROP_DOCUMENT_VALID = "document_valid"; //NOI18N
 
81
    public static final String PROP_SAX_ERROR = "sax_error"; //NOI18N
 
82
    public static final String PROPERTY_DATA_MODIFIED = "data modified";  //NOI18N
 
83
    public static final String PROPERTY_DATA_UPDATED = "data changed";  //NOI18N
 
84
    protected XmlMultiViewEditorSupport editorSupport;
 
85
    private org.xml.sax.SAXException saxError;
 
86
    
 
87
    private final DataCache dataCache = new DataCache();
 
88
    private EncodingHelper encodingHelper = new EncodingHelper();
 
89
    private transient long timeStamp = 0;
 
90
    private transient WeakReference lockReference;
 
91
    
 
92
    
 
93
    private MultiViewElement activeMVElement;
 
94
    
 
95
    private final SaveCookie saveCookie = new SaveCookie() {
 
96
        /** Implements <code>SaveCookie</code> interface. */
 
97
        public void save() throws java.io.IOException {
 
98
            getEditorSupport().saveDocument();
 
99
        }
 
100
    };
 
101
    
 
102
    /** Creates a new instance of XmlMultiViewDataObject */
 
103
    public XmlMultiViewDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException {
 
104
        super(pf, loader);
 
105
        getCookieSet().add(XmlMultiViewEditorSupport.class, this);
 
106
        getCookieSet().assign(FileEncodingQueryImplementation.class, new Object[]{XmlFileEncodingQueryImpl.singleton()});
 
107
    }
 
108
    
 
109
    protected EditorCookie createEditorCookie() {
 
110
        return getEditorSupport();
 
111
    }
 
112
    
 
113
    public org.openide.nodes.Node.Cookie createCookie(Class clazz) {
 
114
        if (clazz.isAssignableFrom(XmlMultiViewEditorSupport.class)) {
 
115
            return getEditorSupport();
 
116
        } else {
 
117
            return null;
 
118
        }
 
119
    }
 
120
    
 
121
    /** Gets editor support for this data object. */
 
122
    protected synchronized XmlMultiViewEditorSupport getEditorSupport() {
 
123
        if(editorSupport == null) {
 
124
            editorSupport = new XmlMultiViewEditorSupport(this);
 
125
            editorSupport.getMultiViewDescriptions();
 
126
        }
 
127
        return editorSupport;
 
128
    }
 
129
    
 
130
    /** enables to switch quickly to XML perspective in multi view editor
 
131
     */
 
132
    public void goToXmlView() {
 
133
        getEditorSupport().goToXmlPerspective();
 
134
    }
 
135
    
 
136
    protected void setSaxError(org.xml.sax.SAXException saxError) {
 
137
        org.xml.sax.SAXException oldError = this.saxError;
 
138
        this.saxError=saxError;
 
139
        if (oldError==null) {
 
140
            if (saxError != null) {
 
141
                firePropertyChange(PROP_DOCUMENT_VALID, Boolean.TRUE, Boolean.FALSE);
 
142
            }
 
143
        } else {
 
144
            if (saxError == null) {
 
145
                firePropertyChange(PROP_DOCUMENT_VALID, Boolean.FALSE, Boolean.TRUE);
 
146
            }
 
147
        }
 
148
        
 
149
        String oldErrorMessage = getErrorMessage(oldError);
 
150
        String newErrorMessage = getErrorMessage(saxError);
 
151
        if (oldErrorMessage==null) {
 
152
            if (newErrorMessage!=null) {
 
153
                firePropertyChange(PROP_SAX_ERROR, null, newErrorMessage);
 
154
            }
 
155
        } else if (!oldErrorMessage.equals(newErrorMessage)) {
 
156
            firePropertyChange(PROP_SAX_ERROR, oldErrorMessage, newErrorMessage);
 
157
        }
 
158
    }
 
159
    
 
160
    private static String getErrorMessage(Exception e) {
 
161
        return e == null ? null : e.getMessage();
 
162
    }
 
163
    
 
164
    public org.xml.sax.SAXException getSaxError() {
 
165
        return saxError;
 
166
    }
 
167
    
 
168
    /** Icon for XML View */
 
169
    protected java.awt.Image getXmlViewIcon() {
 
170
        return org.openide.util.Utilities.loadImage("org/netbeans/modules/xml/multiview/resources/xmlObject.gif"); //NOI18N
 
171
    }
 
172
    
 
173
    /** MultiViewDesc for MultiView editor
 
174
     */
 
175
    protected abstract DesignMultiViewDesc[] getMultiViewDesc();
 
176
    
 
177
    public void setLastOpenView(int index) {
 
178
        getEditorSupport().setLastOpenView(index);
 
179
    }
 
180
    
 
181
    /** provides renaming of super top component */
 
182
    protected FileObject handleRename(String name) throws IOException {
 
183
        FileObject retValue = super.handleRename(name);
 
184
        getEditorSupport().updateDisplayName();
 
185
        return retValue;
 
186
    }
 
187
 
 
188
    public Lookup getLookup() {
 
189
        return getCookieSet().getLookup();
 
190
    }
 
191
    
 
192
    /**
 
193
     * Set whether the object is considered modified.
 
194
     * Also fires a change event.
 
195
     * If the new value is <code>true</code>, the data object is added into a {@link #getRegistry registry} of opened data objects.
 
196
     * If the new value is <code>false</code>,
 
197
     * the data object is removed from the registry.
 
198
     */
 
199
    public void setModified(boolean modif) {
 
200
        super.setModified(modif);
 
201
        //getEditorSupport().updateDisplayName();
 
202
        if (modif) {
 
203
            // Add save cookie
 
204
            if (getCookie(SaveCookie.class) == null) {
 
205
                getCookieSet().add(saveCookie);
 
206
            }
 
207
        } else {
 
208
            // Remove save cookie
 
209
            if(saveCookie.equals(getCookie(SaveCookie.class))) {
 
210
                getCookieSet().remove(saveCookie);
 
211
            }
 
212
            
 
213
        }
 
214
    }
 
215
    
 
216
    public boolean canClose() {
 
217
        final CloneableTopComponent topComponent = ((CloneableTopComponent) getEditorSupport().getMVTC());
 
218
        if (topComponent != null){
 
219
            Enumeration enumeration = topComponent.getReference().getComponents();
 
220
            if (enumeration.hasMoreElements()) {
 
221
                enumeration.nextElement();
 
222
                if (enumeration.hasMoreElements()) {
 
223
                    return true;
 
224
                }
 
225
            }
 
226
        }
 
227
        FileLock lock;
 
228
        try {
 
229
            lock = waitForLock();
 
230
        } catch (IOException e) {
 
231
            ErrorManager.getDefault().notify(e);
 
232
            return !isModified();
 
233
        }
 
234
        try {
 
235
            return !isModified();
 
236
        } finally {
 
237
            lock.releaseLock();
 
238
        }
 
239
    }
 
240
    
 
241
    public FileLock waitForLock() throws IOException {
 
242
        return waitForLock(10000);
 
243
    }
 
244
    
 
245
    public FileLock waitForLock(long timeout) throws IOException {
 
246
        long t = System.currentTimeMillis() + timeout;
 
247
        long sleepTime = 50;
 
248
        for (;;) {
 
249
            try {
 
250
                return dataCache.lock();
 
251
            } catch (IOException e) {
 
252
                if (System.currentTimeMillis() > t) {
 
253
                    throw (IOException) new IOException("Cannot wait for data lock for more than " + timeout + " ms").initCause(e); //NO18N
 
254
                }
 
255
                try {
 
256
                    Thread.sleep(sleepTime);
 
257
                    sleepTime = 3 * sleepTime / 2; 
 
258
                } catch (InterruptedException e1) {
 
259
                    //
 
260
                }
 
261
            }
 
262
        }
 
263
    }
 
264
    
 
265
    public org.netbeans.core.api.multiview.MultiViewPerspective getSelectedPerspective() {
 
266
        return getEditorSupport().getSelectedPerspective();
 
267
    }
 
268
    
 
269
    /** Enable to focus specific object in Multiview Editor
 
270
     *  The default implementation opens the XML View.
 
271
     */
 
272
    public void showElement(Object element) {
 
273
        getEditorSupport().edit();
 
274
    }
 
275
    
 
276
    /** Enable to get active MultiViewElement object
 
277
     */
 
278
    protected MultiViewElement getActiveMultiViewElement() {
 
279
        return activeMVElement;
 
280
    }
 
281
    void setActiveMultiViewElement(MultiViewElement element) {
 
282
        activeMVElement = element;
 
283
    }
 
284
    /** Opens the specific view
 
285
     * @param index multi-view index
 
286
     */
 
287
    public void openView(int index) {
 
288
        getEditorSupport().openView(index);
 
289
    }
 
290
    
 
291
    protected abstract String getPrefixMark();
 
292
    
 
293
    boolean acceptEncoding() throws IOException {
 
294
        encodingHelper.resetEncoding();
 
295
        DataCache dataCache = getDataCache();
 
296
        String s = dataCache.getStringData();
 
297
        String encoding = encodingHelper.detectEncoding(s.getBytes());
 
298
        if (!encodingHelper.getEncoding().equals(encoding)) {
 
299
            Object result = showChangeEncodingDialog(encoding);
 
300
            if (NotifyDescriptor.YES_OPTION.equals(result)) {
 
301
                dataCache.setData(encodingHelper.setDefaultEncoding(s));
 
302
            } else if (NotifyDescriptor.NO_OPTION.equals(result)) {
 
303
                showUsingDifferentEncodingMessage(encoding);
 
304
            } else {
 
305
                return false;
 
306
            }
 
307
        }
 
308
        return true;
 
309
    }
 
310
    
 
311
    private void showUsingDifferentEncodingMessage(String encoding) {
 
312
        String message = NbBundle.getMessage(XmlMultiViewDataObject.class, "TEXT_TREAT_USING_DIFFERENT_ENCODING", encoding,
 
313
                encodingHelper.getEncoding());
 
314
        NotifyDescriptor.Message descriptor = new NotifyDescriptor.Message(message);
 
315
        descriptor.setTitle(getPrimaryFile().getPath());
 
316
        DialogDisplayer.getDefault().notify(descriptor);
 
317
    }
 
318
    
 
319
    private Object showChangeEncodingDialog(String encoding) {
 
320
        String message = NbBundle.getMessage(Utils.class, "TEXT_CHANGE_DECLARED_ENCODING", encoding,
 
321
                encodingHelper.getEncoding());
 
322
        NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(message, getPrimaryFile().getPath(),
 
323
                NotifyDescriptor.YES_NO_CANCEL_OPTION);
 
324
        return DialogDisplayer.getDefault().notify(descriptor);
 
325
    }
 
326
    
 
327
    public EncodingHelper getEncodingHelper() {
 
328
        return encodingHelper;
 
329
    }
 
330
    
 
331
    public DataCache getDataCache() {
 
332
        return dataCache;
 
333
    }
 
334
    
 
335
    /** Is that necesary for this class to be public ?
 
336
     *  It can be changed to interface
 
337
     */
 
338
    public class DataCache {
 
339
        
 
340
        // What about using the StringBuffer instead ?
 
341
        private transient String buffer = null;
 
342
        private long fileTime = 0;
 
343
        
 
344
        public void loadData() {
 
345
            FileObject file = getPrimaryFile();
 
346
            if (fileTime == file.lastModified().getTime()) {
 
347
                return;
 
348
            }
 
349
            try {
 
350
                FileLock dataLock = lock();
 
351
                loadData(file, dataLock);
 
352
            } catch (IOException e) {
 
353
                if (buffer == null) {
 
354
                    buffer = ""; //NOI18N
 
355
                }
 
356
            }
 
357
        }
 
358
        
 
359
        /**
 
360
         * Updates the data cache with the contents of the associated file. 
 
361
         * Unlike {@link #loadData()}, tries to use existing lock before attempting
 
362
         * to acquire a new lock.
 
363
         */
 
364
        public void reloadData() throws IOException{
 
365
            FileObject file = getPrimaryFile();
 
366
            if (fileTime == file.lastModified().getTime()) {
 
367
                return;
 
368
            }
 
369
            FileLock lock = getLock();
 
370
            if (lock == null){
 
371
                lock = lock();
 
372
            }
 
373
            loadData(file, lock);
 
374
            
 
375
        }
 
376
        /** Does this method need to be public ?
 
377
         */
 
378
        public void loadData(FileObject file, FileLock dataLock) throws IOException {
 
379
            try {
 
380
                BufferedInputStream inputStream = new BufferedInputStream(file.getInputStream());
 
381
                String encoding = encodingHelper.detectEncoding(inputStream);
 
382
                if (!encodingHelper.getEncoding().equals(encoding)) {
 
383
                    showUsingDifferentEncodingMessage(encoding);
 
384
                }
 
385
                Reader reader = new InputStreamReader(inputStream, encodingHelper.getEncoding());
 
386
                long time;
 
387
                StringBuffer sb = new StringBuffer(2048);
 
388
                try {
 
389
                    char[] buf = new char[1024];
 
390
                    time = file.lastModified().getTime();
 
391
                    int i;
 
392
                    while ((i = reader.read(buf,0,1024)) != -1) {
 
393
                        sb.append(buf,0,i);
 
394
                    }
 
395
                } finally {
 
396
                    reader.close();
 
397
                }
 
398
                buffer = null;
 
399
                fileTime = time;
 
400
                setData(dataLock, sb.toString(), true);
 
401
            } finally {
 
402
                dataLock.releaseLock();
 
403
            }
 
404
        }
 
405
        /** Is the second argument necessary ?
 
406
         */
 
407
        public void setData(FileLock lock, String s, boolean modify) throws IOException {
 
408
            testLock(lock);
 
409
            boolean modified = isModified() || modify;
 
410
            long oldTimeStamp = timeStamp;
 
411
            if (setData(s)) {
 
412
                if (!modified) {
 
413
                    saveData(lock);
 
414
                    firePropertyChange(PROPERTY_DATA_UPDATED, new Long(oldTimeStamp), new Long(timeStamp));
 
415
                } else {
 
416
                    firePropertyChange(PROPERTY_DATA_MODIFIED, new Long(oldTimeStamp), new Long(timeStamp));
 
417
                }
 
418
            } 
 
419
        }
 
420
        
 
421
        private boolean setData(String s) {
 
422
            // ??? when this can happen
 
423
            if (s.equals(buffer)) {
 
424
                return false;
 
425
            }
 
426
            buffer = s;
 
427
            long newTimeStamp = new Date().getTime();
 
428
            if (newTimeStamp <= timeStamp) {
 
429
                newTimeStamp = timeStamp + 1;
 
430
            }
 
431
            timeStamp = newTimeStamp;
 
432
            fileTime = 0;
 
433
            return true;
 
434
        }
 
435
        
 
436
        public synchronized void saveData(FileLock dataLock) {
 
437
            if (buffer == null || fileTime == getPrimaryFile().lastModified().getTime()) {
 
438
                return;
 
439
            }
 
440
            
 
441
            try {
 
442
                XmlMultiViewEditorSupport editorSupport = getEditorSupport();
 
443
                if (editorSupport.getDocument() == null) {
 
444
                    XmlMultiViewEditorSupport.XmlEnv xmlEnv = editorSupport.getXmlEnv();
 
445
                    FileLock lock = xmlEnv.takeLock();
 
446
                    OutputStream outputStream = getPrimaryFile().getOutputStream(lock);
 
447
                    Writer writer = new OutputStreamWriter(outputStream, encodingHelper.getEncoding());
 
448
                    try {
 
449
                        writer.write(buffer);
 
450
                    } finally {
 
451
                        writer.close();
 
452
                        lock.releaseLock();
 
453
                        xmlEnv.unmarkModified();
 
454
                        resetFileTime();
 
455
                    }
 
456
                } else {
 
457
                    editorSupport.saveDocument(dataLock);
 
458
                }
 
459
            } catch (IOException e) {
 
460
                ErrorManager.getDefault().notify(e);
 
461
            }
 
462
        }
 
463
        
 
464
        public FileLock lock() throws IOException {
 
465
            FileLock current = getLock();
 
466
            if (current != null) {
 
467
                throw new FileAlreadyLockedException("File is already locked by [" + current + "]."); // NO18N
 
468
            }
 
469
            FileLock l = new FileLock();
 
470
            lockReference = new WeakReference(l);
 
471
            return l;
 
472
        }
 
473
        
 
474
        private FileLock getLock() {
 
475
            // How this week reference can be useful ?
 
476
            FileLock l = lockReference == null ? null : (FileLock) lockReference.get();
 
477
            if (l != null && !l.isValid()) {
 
478
                l = null;
 
479
            }
 
480
            return l;
 
481
        }
 
482
        
 
483
        public String getStringData() {
 
484
            if (buffer == null) {
 
485
                loadData();
 
486
            }
 
487
            return buffer;
 
488
        }
 
489
        
 
490
        public byte[] getData() {
 
491
            try {
 
492
                return getStringData().getBytes(encodingHelper.getEncoding());
 
493
            } catch (UnsupportedEncodingException e) {
 
494
                ErrorManager.getDefault().notify(e);
 
495
                return null;  // should not happen
 
496
            }
 
497
        }
 
498
        
 
499
        public void setData(FileLock lock, byte[] data, boolean modify) throws IOException {
 
500
            encodingHelper.detectEncoding(data);
 
501
            setData(lock, new String(data, encodingHelper.getEncoding()), modify);
 
502
        }
 
503
        
 
504
        public long getTimeStamp() {
 
505
            return timeStamp;
 
506
        }
 
507
        
 
508
        public InputStream createInputStream() {
 
509
            try {
 
510
                encodingHelper.detectEncoding(getStringData().getBytes());
 
511
                return new ReaderInputStream(new StringReader(getStringData()), encodingHelper.getEncoding());
 
512
            } catch (IOException e) {
 
513
                ErrorManager.getDefault().notify(e);
 
514
                return null;
 
515
            }
 
516
        }
 
517
        
 
518
        public Reader createReader() throws IOException {
 
519
            return new StringReader(getStringData());
 
520
        }
 
521
        
 
522
        public OutputStream createOutputStream() throws IOException {
 
523
            final FileLock dataLock = lock();
 
524
            return new ByteArrayOutputStream() {
 
525
                public void close() throws IOException {
 
526
                    try {
 
527
                        super.close();
 
528
                        setData(dataLock, toByteArray(), true);
 
529
                    } finally {
 
530
                        dataLock.releaseLock();
 
531
                    }
 
532
                }
 
533
            };
 
534
        }
 
535
        
 
536
        public OutputStream createOutputStream(final FileLock dataLock, final boolean modify) throws IOException {
 
537
            testLock(dataLock);
 
538
            return new ByteArrayOutputStream() {
 
539
                public void close() throws IOException {
 
540
                    super.close();
 
541
                    setData(dataLock, toByteArray(), modify);
 
542
                    if (!modify) {
 
543
                        dataCache.saveData(dataLock);
 
544
                    }
 
545
                }
 
546
            };
 
547
        }
 
548
        
 
549
        public Writer createWriter() throws IOException {
 
550
            final FileLock dataLock = lock();
 
551
            return new StringWriter() {
 
552
                public void close() throws IOException {
 
553
                    try {
 
554
                        super.close();
 
555
                        setData(dataLock, toString(), true);
 
556
                    } finally {
 
557
                        dataLock.releaseLock();
 
558
                    }
 
559
                }
 
560
            };
 
561
        }
 
562
        
 
563
        public Writer createWriter(final FileLock dataLock, final boolean modify) throws IOException {
 
564
            testLock(dataLock);
 
565
            return new StringWriter() {
 
566
                public void close() throws IOException {
 
567
                    super.close();
 
568
                    setData(dataLock, toString(), modify);
 
569
                    if (!modify) {
 
570
                        dataCache.saveData(dataLock);
 
571
                    }
 
572
                }
 
573
            };
 
574
        }
 
575
        
 
576
        public void testLock(FileLock lock) throws IOException {
 
577
            if (lock == null) {
 
578
                throw new IOException("Lock is null."); //NO18N
 
579
            } else if (lock != getLock()){
 
580
                throw new IOException("Invalid lock [" + lock + "]. Expected [" + getLock() + "]."); //NO18N
 
581
            }
 
582
        }
 
583
        
 
584
        public void resetFileTime() {
 
585
            fileTime = getPrimaryFile().lastModified().getTime();
 
586
        }
 
587
    }
 
588
}