This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 146072
Collapse All | Expand All

(-)a/java.j2seproject/nbproject/project.xml (-1 / +1 lines)
Lines 180-186 Link Here
180
                    <compile-dependency/>
180
                    <compile-dependency/>
181
                    <run-dependency>
181
                    <run-dependency>
182
                        <release-version>1</release-version>
182
                        <release-version>1</release-version>
183
                        <specification-version>1.25</specification-version>
183
                        <specification-version>1.26</specification-version>
184
                    </run-dependency>
184
                    </run-dependency>
185
                </dependency>
185
                </dependency>
186
                <dependency>
186
                <dependency>
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEConfigurationProvider.java (-23 / +24 lines)
Lines 103-137 Link Here
103
    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
103
    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
104
    private final FileChangeListener fcl = new FileChangeAdapter() {
104
    private final FileChangeListener fcl = new FileChangeAdapter() {
105
        public void fileFolderCreated(FileEvent fe) {
105
        public void fileFolderCreated(FileEvent fe) {
106
            update(fe);
106
            updateConfigurations(fe);
107
        }
107
        }
108
        public void fileDataCreated(FileEvent fe) {
108
        public void fileDataCreated(FileEvent fe) {
109
            update(fe);
109
            updateConfigurations(fe);
110
        }
110
        }
111
        public void fileDeleted(FileEvent fe) {
111
        public void fileDeleted(FileEvent fe) {
112
            update(fe);
112
            updateConfigurations(fe);
113
        }
113
        }
114
        public void fileRenamed(FileRenameEvent fe) {
114
        public void fileRenamed(FileRenameEvent fe) {
115
            update(fe);
115
            updateConfigurations(fe);
116
        }
117
        private void update(FileEvent ev) {
118
            LOGGER.log(Level.FINEST, "Received {0}", ev);
119
            Set<String> oldConfigs = configs != null ? configs.keySet() : Collections.<String>emptySet();
120
            configDir = p.getProjectDirectory().getFileObject("nbproject/configs"); // NOI18N
121
            if (configDir != null) {
122
                configDir.removeFileChangeListener(fclWeak);
123
                configDir.addFileChangeListener(fclWeak);
124
                LOGGER.log(Level.FINEST, "(Re-)added listener to {0}", configDir);
125
            } else {
126
                LOGGER.log(Level.FINEST, "No nbproject/configs exists");
127
            }
128
            calculateConfigs();
129
            Set<String> newConfigs = configs.keySet();
130
            if (!oldConfigs.equals(newConfigs)) {
131
                LOGGER.log(Level.FINER, "Firing " + ProjectConfigurationProvider.PROP_CONFIGURATIONS + ": {0} -> {1}", new Object[] {oldConfigs, newConfigs});
132
                pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATIONS, null, null);
133
                // XXX also fire PROP_ACTIVE_CONFIGURATION?
134
            }
135
        }
116
        }
136
    };
117
    };
137
    private final FileChangeListener fclWeak;
118
    private final FileChangeListener fclWeak;
Lines 155-165 Link Here
155
        p.evaluator().addPropertyChangeListener(new PropertyChangeListener() {
136
        p.evaluator().addPropertyChangeListener(new PropertyChangeListener() {
156
            public void propertyChange(PropertyChangeEvent evt) {
137
            public void propertyChange(PropertyChangeEvent evt) {
157
                if (PROP_CONFIG.equals(evt.getPropertyName())) {
138
                if (PROP_CONFIG.equals(evt.getPropertyName())) {
139
                    updateConfigurations(null);
158
                    LOGGER.log(Level.FINER, "Refiring " + PROP_CONFIG + " -> " + ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE);
140
                    LOGGER.log(Level.FINER, "Refiring " + PROP_CONFIG + " -> " + ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE);
159
                    pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE, null, null);
141
                    pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE, null, null);
160
                }
142
                }
161
            }
143
            }
162
        });
144
        });
145
    }
146
    private void updateConfigurations(FileEvent ev) {
147
        LOGGER.log(Level.FINEST, "Received {0}", ev);
148
        Set<String> oldConfigs = configs != null ? configs.keySet() : Collections.<String>emptySet();
149
        configDir = p.getProjectDirectory().getFileObject("nbproject/configs"); // NOI18N
150
        if (configDir != null) {
151
            configDir.removeFileChangeListener(fclWeak);
152
            configDir.addFileChangeListener(fclWeak);
153
            LOGGER.log(Level.FINEST, "(Re-)added listener to {0}", configDir);
154
        } else {
155
            LOGGER.log(Level.FINEST, "No nbproject/configs exists");
156
        }
157
        calculateConfigs();
158
        Set<String> newConfigs = configs.keySet();
159
        if (!oldConfigs.equals(newConfigs)) {
160
            LOGGER.log(Level.FINER, "Firing " + ProjectConfigurationProvider.PROP_CONFIGURATIONS + ": {0} -> {1}", new Object[] {oldConfigs, newConfigs});
161
            pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATIONS, null, null);
162
            // XXX also fire PROP_ACTIVE_CONFIGURATION?
163
        }
163
    }
164
    }
164
165
165
    private void calculateConfigs() {
166
    private void calculateConfigs() {
(-)a/java.j2seproject/test/unit/src/org/netbeans/modules/java/j2seproject/J2SEConfigurationProviderTest.java (-2 / +24 lines)
Lines 230-237 Link Here
230
                return null;
230
                return null;
231
            }
231
            }
232
        });
232
        });
233
        //todo: workaround, fix me!
234
        Thread.sleep(1000);
235
        ProjectManager.mutex().readAccess(new Mutex.ExceptionAction<Void>() {
233
        ProjectManager.mutex().readAccess(new Mutex.ExceptionAction<Void>() {
236
                public Void run () throws Exception {
234
                public Void run () throws Exception {
237
                    assertEquals(new HashSet<String>(Arrays.asList(ProjectConfigurationProvider.PROP_CONFIGURATIONS, ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE)),
235
                    assertEquals(new HashSet<String>(Arrays.asList(ProjectConfigurationProvider.PROP_CONFIGURATIONS, ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE)),
Lines 243-248 Link Here
243
        });                
241
        });                
244
    }
242
    }
245
243
244
    public void testInitialListeningInOneSection() throws Exception { // #84781
245
        final TestListener l = new TestListener();
246
        ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Void>() {
247
            public Void run() throws Exception {
248
                pcp.addPropertyChangeListener(l);
249
                EditableProperties props = new EditableProperties();
250
                props.setProperty("$label", "X");
251
                write(props, d, "nbproject/configs/x.properties");
252
                EditableProperties p2 = new EditableProperties();
253
                p2.setProperty("config", "x");
254
                write(p2, d, "nbproject/private/config.properties");
255
                assertEquals(new HashSet<String>(Arrays.asList(ProjectConfigurationProvider.PROP_CONFIGURATIONS, ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE)),
256
                    l.events());
257
                assertEquals(2, pcp.getConfigurations().size());
258
                assertEquals("X", pcp.getActiveConfiguration().getDisplayName());
259
                return null;
260
            }
261
        });
262
    }
263
264
    private void write(EditableProperties p, FileObject d, String path) throws IOException {
265
        FileObject f = FileUtil.createData(d, path);
266
        p.store(f);
267
    }
246
    private void write(Properties p, FileObject d, String path) throws IOException {
268
    private void write(Properties p, FileObject d, String path) throws IOException {
247
        FileObject f = FileUtil.createData(d, path);
269
        FileObject f = FileUtil.createData(d, path);
248
        OutputStream os = f.getOutputStream();
270
        OutputStream os = f.getOutputStream();
(-)a/project.ant/apichanges.xml (+20 lines)
Lines 105-110 Link Here
105
105
106
    <changes>
106
    <changes>
107
107
108
        <change id="ep-store">
109
            <api name="general"/>
110
            <summary>EditableProperties.store helper method</summary>
111
            <version major="1" minor="26"/>
112
            <date day="15" month="9" year="2008"/>
113
            <author login="mkubec"/>
114
            <compatibility addition="yes"/>
115
            <description>
116
                <p>
117
                    Helper <a href="org/netbeans/spi/project/support/ant/EditableProperties.html#store(org.openide.filesystems.FileObject)">
118
                    method</a> to store <code>EditableProperties</code>
119
                    into a <code>FileObject</code> has been added.
120
                    <code>AntProjectHelper.createSimpleAntArtifact</code> enhanced
121
                    with new parameter: property name holding project relative location
122
                    and name of Ant build script to use.
123
                </p>
124
            </description>
125
            <class package="org.netbeans.spi.project.support.ant" name="EditableProperties"/>
126
            <issue number="146072"/>
127
        </change>
108
        <change id="antartifact-enhancement">
128
        <change id="antartifact-enhancement">
109
            <api name="general"/>
129
            <api name="general"/>
110
            <summary>Enhance AntArtifact support with ability to specify build.xml location and name</summary>
130
            <summary>Enhance AntArtifact support with ability to specify build.xml location and name</summary>
(-)a/project.ant/manifest.mf (-1 / +1 lines)
Lines 1-6 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.project.ant/1
2
OpenIDE-Module: org.netbeans.modules.project.ant/1
3
OpenIDE-Module-Specification-Version: 1.25
3
OpenIDE-Module-Specification-Version: 1.26
4
OpenIDE-Module-Layer: org/netbeans/modules/project/ant/resources/mf-layer.xml
4
OpenIDE-Module-Layer: org/netbeans/modules/project/ant/resources/mf-layer.xml
5
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/project/ant/Bundle.properties
5
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/project/ant/Bundle.properties
6
OpenIDE-Module-Install: org/netbeans/modules/project/ant/AntProjectModule.class
6
OpenIDE-Module-Install: org/netbeans/modules/project/ant/AntProjectModule.class
(-)a/project.ant/nbproject/project.xml (-1 / +1 lines)
Lines 78-84 Link Here
78
                    <compile-dependency/>
78
                    <compile-dependency/>
79
                    <run-dependency>
79
                    <run-dependency>
80
                        <release-version>1</release-version>
80
                        <release-version>1</release-version>
81
                        <specification-version>1.17</specification-version>
81
                        <specification-version>1.20</specification-version>
82
                    </run-dependency>
82
                    </run-dependency>
83
                </dependency>
83
                </dependency>
84
                <dependency>
84
                <dependency>
(-)a/project.ant/src/org/netbeans/api/project/ant/AntBuildExtender.java (-15 / +3 lines)
Lines 272-292 Link Here
272
                    propValue.delete(propValue.length() - 1, propValue.length());
272
                    propValue.delete(propValue.length() - 1, propValue.length());
273
                    
273
                    
274
                    editableProps.setProperty(propName, propValue.toString());
274
                    editableProps.setProperty(propName, propValue.toString());
275
                    
275
276
                    OutputStream os = null;
276
277
                    FileLock lock = null;
277
                    editableProps.store(projPropsFO);
278
                    try {
279
                        lock = projPropsFO.lock();
280
                        os = projPropsFO.getOutputStream(lock);
281
                        editableProps.store(os);
282
                    } finally {
283
                        if (lock != null) {
284
                            lock.releaseLock();
285
                        }
286
                        if (os != null) {
287
                            os.close();
288
                        }
289
                    }
290
                    return null;
278
                    return null;
291
                }
279
                }
292
            });
280
            });
(-)a/project.ant/src/org/netbeans/modules/project/ant/FileChangeSupport.java (-9 / +56 lines)
Lines 48-53 Link Here
48
import java.lang.ref.WeakReference;
48
import java.lang.ref.WeakReference;
49
import java.util.HashMap;
49
import java.util.HashMap;
50
50
51
import java.util.LinkedHashSet;
52
import java.util.LinkedList;
53
import java.util.List;
54
import java.util.Set;
51
import org.openide.filesystems.FileChangeListener;
55
import org.openide.filesystems.FileChangeListener;
52
import org.openide.filesystems.FileAttributeEvent;
56
import org.openide.filesystems.FileAttributeEvent;
53
import org.openide.filesystems.FileEvent;
57
import org.openide.filesystems.FileEvent;
Lines 112-123 Link Here
112
            f2H.remove(path);
116
            f2H.remove(path);
113
        }
117
        }
114
    }
118
    }
119
120
    public void notifyChange(File f) {
121
        Set<Holder> fireTo = new LinkedHashSet<Holder>();
122
        synchronized (holders) {
123
            for (Map.Entry<FileChangeSupportListener, Map<File, Holder>> e : holders.entrySet()) {
124
                Holder h = e.getValue().get(f);
125
                if (h != null) {
126
                    fireTo.add(h);
127
                }
128
                h = e.getValue().get(f.getParentFile());
129
                if (h != null) {
130
                    fireTo.add(h);
131
                }
132
            }
133
        }
134
        if (fireTo.isEmpty()) {
135
            return;
136
        }
137
        long now = System.currentTimeMillis();
138
        for (Holder holder : fireTo) {
139
            holder.last = now;
140
        }
141
        FileObject who = FileUtil.toFileObject(f);
142
        for (Holder holder : fireTo) {
143
            holder.toNotify = true;
144
        }
145
        if (who != null) {
146
            who.refresh(true);
147
        }
148
        for (Holder holder : fireTo) {
149
            if (holder.toNotify) {
150
                holder.someChange(System.currentTimeMillis(), null, who);
151
            }
152
        }
153
    }
115
    
154
    
116
    private static final class Holder extends WeakReference<FileChangeSupportListener> implements FileChangeListener, Runnable {
155
    private static final class Holder extends WeakReference<FileChangeSupportListener> implements FileChangeListener, Runnable {
117
        
156
        
118
        private final File path;
157
        private final File path;
119
        private FileObject current;
158
        private FileObject current;
120
        private File currentF;
159
        private File currentF;
160
        private long last;
161
        boolean toNotify;
121
        
162
        
122
        public Holder(FileChangeSupportListener listener, File path) {
163
        public Holder(FileChangeSupportListener listener, File path) {
123
            super(listener, Utilities.activeReferenceQueue());
164
            super(listener, Utilities.activeReferenceQueue());
Lines 158-164 Link Here
158
            }
199
            }
159
        }
200
        }
160
201
161
        private void someChange(FileObject modified) {
202
        private void someChange(long time, FileEvent orig, FileObject modified) {
203
            if (orig != null && orig.getTime() < last) {
204
                return;
205
            }
206
            last = time;
207
            toNotify = false;
208
162
            FileChangeSupportListener listener;
209
            FileChangeSupportListener listener;
163
            FileObject oldCurrent, nueCurrent;
210
            FileObject oldCurrent, nueCurrent;
164
            File oldCurrentF, nueCurrentF;
211
            File oldCurrentF, nueCurrentF;
Lines 177-215 Link Here
177
                nueCurrentF = currentF;
224
                nueCurrentF = currentF;
178
            }
225
            }
179
            if (modified != null && modified == nueCurrent) {
226
            if (modified != null && modified == nueCurrent) {
180
                FileChangeSupportEvent event = new FileChangeSupportEvent(DEFAULT, FileChangeSupportEvent.EVENT_MODIFIED, path);
227
                FileChangeSupportEvent event = new FileChangeSupportEvent(orig, DEFAULT, FileChangeSupportEvent.EVENT_MODIFIED, path);
181
                listener.fileModified(event);
228
                listener.fileModified(event);
182
            } else {
229
            } else {
183
                boolean oldWasCorrect = path.equals(oldCurrentF);
230
                boolean oldWasCorrect = path.equals(oldCurrentF);
184
                boolean nueIsCorrect = path.equals(nueCurrentF);
231
                boolean nueIsCorrect = path.equals(nueCurrentF);
185
                if (oldWasCorrect && !nueIsCorrect) {
232
                if (oldWasCorrect && !nueIsCorrect) {
186
                    FileChangeSupportEvent event = new FileChangeSupportEvent(DEFAULT, FileChangeSupportEvent.EVENT_DELETED, path);
233
                    FileChangeSupportEvent event = new FileChangeSupportEvent(orig, DEFAULT, FileChangeSupportEvent.EVENT_DELETED, path);
187
                    listener.fileDeleted(event);
234
                    listener.fileDeleted(event);
188
                } else if (nueIsCorrect && !oldWasCorrect) {
235
                } else if (nueIsCorrect && !oldWasCorrect) {
189
                    FileChangeSupportEvent event = new FileChangeSupportEvent(DEFAULT, FileChangeSupportEvent.EVENT_CREATED, path);
236
                    FileChangeSupportEvent event = new FileChangeSupportEvent(orig, DEFAULT, FileChangeSupportEvent.EVENT_CREATED, path);
190
                    listener.fileCreated(event);
237
                    listener.fileCreated(event);
191
                }
238
                }
192
            }
239
            }
193
        }
240
        }
194
241
195
        public void fileChanged(FileEvent fe) {
242
        public void fileChanged(FileEvent fe) {
196
            someChange(fe.getFile());
243
            someChange(0, fe, fe.getFile());
197
        }
244
        }
198
        
245
        
199
        public void fileDeleted(FileEvent fe) {
246
        public void fileDeleted(FileEvent fe) {
200
            someChange(null);
247
            someChange(0, fe, null);
201
        }
248
        }
202
249
203
        public void fileDataCreated(FileEvent fe) {
250
        public void fileDataCreated(FileEvent fe) {
204
            someChange(null);
251
            someChange(0, fe, null);
205
        }
252
        }
206
253
207
        public void fileFolderCreated(FileEvent fe) {
254
        public void fileFolderCreated(FileEvent fe) {
208
            someChange(null);
255
            someChange(0, fe, null);
209
        }
256
        }
210
257
211
        public void fileRenamed(FileRenameEvent fe) {
258
        public void fileRenamed(FileRenameEvent fe) {
212
            someChange(null);
259
            someChange(0, fe, null);
213
        }
260
        }
214
        
261
        
215
        public void fileAttributeChanged(FileAttributeEvent fe) {
262
        public void fileAttributeChanged(FileAttributeEvent fe) {
(-)a/project.ant/src/org/netbeans/modules/project/ant/FileChangeSupportEvent.java (-1 / +9 lines)
Lines 44-49 Link Here
44
44
45
import java.util.EventObject;
45
import java.util.EventObject;
46
46
47
import org.openide.filesystems.FileEvent;
47
import org.openide.filesystems.FileObject;
48
import org.openide.filesystems.FileObject;
48
49
49
import org.openide.filesystems.FileUtil;
50
import org.openide.filesystems.FileUtil;
Lines 60-70 Link Here
60
61
61
    private final int type;
62
    private final int type;
62
    private final File path;
63
    private final File path;
64
    private final FileEvent original;
63
    
65
    
64
    FileChangeSupportEvent(FileChangeSupport support, int type, File path) {
66
    FileChangeSupportEvent(FileEvent orig, FileChangeSupport support, int type, File path) {
65
        super(support);
67
        super(support);
66
        this.type = type;
68
        this.type = type;
67
        this.path = path;
69
        this.path = path;
70
        this.original = orig;
68
    }
71
    }
69
    
72
    
70
    public int getType() {
73
    public int getType() {
Lines 78-84 Link Here
78
    public FileObject getFileObject() {
81
    public FileObject getFileObject() {
79
        return FileUtil.toFileObject(path);
82
        return FileUtil.toFileObject(path);
80
    }
83
    }
84
85
    public FileEvent getOriginal() {
86
        return original;
87
    }
81
    
88
    
89
    @Override
82
    public String toString() {
90
    public String toString() {
83
        return "FCSE[" + "CDM".charAt(type) + ":" + path + "]"; // NOI18N
91
        return "FCSE[" + "CDM".charAt(type) + ":" + path + "]"; // NOI18N
84
    }
92
    }
(-)a/project.ant/src/org/netbeans/modules/project/ant/ProjectLibraryProvider.java (-6 / +1 lines)
Lines 752-763 Link Here
752
            ep.remove(key);
752
            ep.remove(key);
753
        }
753
        }
754
        FileObject fo = FileUtil.createData(propfile);
754
        FileObject fo = FileUtil.createData(propfile);
755
        OutputStream os = fo.getOutputStream();
755
        ep.store(fo);
756
        try {
757
            ep.store(os);
758
        } finally {
759
            os.close();
760
        }
761
    }
756
    }
762
757
763
    static final class ProjectLibraryArea implements LibraryStorageArea {
758
    static final class ProjectLibraryArea implements LibraryStorageArea {
(-)a/project.ant/src/org/netbeans/spi/project/support/ant/EditableProperties.java (+34 lines)
Lines 60-65 Link Here
60
import java.util.Map;
60
import java.util.Map;
61
import java.util.NoSuchElementException;
61
import java.util.NoSuchElementException;
62
import java.util.Set;
62
import java.util.Set;
63
import org.netbeans.modules.project.ant.FileChangeSupport;
64
import org.openide.filesystems.FileLock;
65
import org.openide.filesystems.FileObject;
66
import org.openide.filesystems.FileSystem.AtomicAction;
67
import org.openide.filesystems.FileUtil;
63
68
64
// XXX: consider adding getInitialComment() and setInitialComment() methods
69
// XXX: consider adding getInitialComment() and setInitialComment() methods
65
// (useful e.g. for GeneratedFilesHelper)
70
// (useful e.g. for GeneratedFilesHelper)
Lines 230-235 Link Here
230
            }
235
            }
231
        }
236
        }
232
        output.flush();
237
        output.flush();
238
    }
239
240
    /**
241
     * Store properties to a file object. Helper method that deals with opening
242
     * and closing of the file object.
243
     * @param fo file object to store the stream to
244
     * @throws IOException if the stream could not be written to
245
     * @since 1.26
246
     */
247
    public void store(final FileObject fo) throws IOException {
248
        FileUtil.runAtomicAction(new AtomicAction() {
249
            public void run() throws IOException {
250
                OutputStream os = null;
251
                FileLock lock = null;
252
                try {
253
                    lock = fo.lock();
254
                    os = fo.getOutputStream(lock);
255
                    store(os);
256
                } finally {
257
                    if (lock != null) {
258
                        lock.releaseLock();
259
                    }
260
                    if (os != null) {
261
                        os.close();
262
                    }
263
                }
264
                FileChangeSupport.DEFAULT.notifyChange(FileUtil.toFile(fo));
265
            }
266
        });
233
    }
267
    }
234
268
235
    @Override
269
    @Override
(-)a/project.ant/src/org/netbeans/spi/project/support/ant/GeneratedFilesHelper.java (-6 / +6 lines)
Lines 356-374 Link Here
356
                                    try {
356
                                    try {
357
                                        FileLock lock2 = _genfiles.lock();
357
                                        FileLock lock2 = _genfiles.lock();
358
                                        try {
358
                                        try {
359
                                            OutputStream os1 = new EolFilterOutputStream(buildScriptXml.getOutputStream(lock1));
359
                                        OutputStream os1 = new EolFilterOutputStream(buildScriptXml.getOutputStream(lock1));
360
                                            try {
360
                                        try {
361
                                                OutputStream os2 = _genfiles.getOutputStream(lock2);
361
                                                OutputStream os2 = _genfiles.getOutputStream(lock2);
362
                                                try {
362
                                                try {
363
                                                    os1.write(resultData);
363
                                                    os1.write(resultData);
364
                                                    p.store(os2);
364
                                                    p.store(os2);
365
                                                } finally {
365
                                        } finally {
366
                                                    os2.close();
366
                                                    os2.close();
367
                                                }
367
                                                }
368
                                            } finally {
368
                                            } finally {
369
                                                os1.close();
369
                                            os1.close();
370
                                            }
370
                                        }
371
                                        } finally {
371
                                    } finally {
372
                                            lock2.releaseLock();
372
                                            lock2.releaseLock();
373
                                        }
373
                                        }
374
                                    } finally {
374
                                    } finally {
(-)a/project.ant/src/org/netbeans/spi/project/support/ant/ProjectProperties.java (-8 / +13 lines)
Lines 207-213 Link Here
207
                } else {
207
                } else {
208
                    properties = null;
208
                    properties = null;
209
                }
209
                }
210
                fireChange();
210
                fireChange(null);
211
            }
211
            }
212
            return modifying;
212
            return modifying;
213
        }
213
        }
Lines 282-288 Link Here
282
                                    private void reload() {
282
                                    private void reload() {
283
                                        helper.cancelPendingHook();
283
                                        helper.cancelPendingHook();
284
                                        // Revert the save.
284
                                        // Revert the save.
285
                                        diskChange();
285
                                        diskChange(null);
286
                                    }
286
                                    }
287
                                });
287
                                });
288
                            }
288
                            }
Lines 323-329 Link Here
323
            cs.removeChangeListener(l);
323
            cs.removeChangeListener(l);
324
        }
324
        }
325
        
325
        
326
        private void fireChange() {
326
        private void fireChange(FileChangeSupportEvent ev) {
327
            if (!cs.hasListeners()) {
327
            if (!cs.hasListeners()) {
328
                return;
328
                return;
329
            }
329
            }
Lines 333-338 Link Here
333
                    return null;
333
                    return null;
334
                }
334
                }
335
            };
335
            };
336
            if (ev != null && ev.getOriginal() != null && ProjectManager.isMutexEvent(ev.getOriginal())) {
337
                ProjectManager.mutex().readAccess(action);
338
                return;
339
            }
340
            
336
            if (ProjectManager.mutex().isWriteAccess()) {
341
            if (ProjectManager.mutex().isWriteAccess()) {
337
                // Run it right now. postReadRequest would be too late.
342
                // Run it right now. postReadRequest would be too late.
338
                ProjectManager.mutex().readAccess(action);
343
                ProjectManager.mutex().readAccess(action);
Lines 349-375 Link Here
349
            }
354
            }
350
        }
355
        }
351
        
356
        
352
        private void diskChange() {
357
        private void diskChange(FileChangeSupportEvent ev) {
353
            // XXX should check for a possible clobber from in-memory data
358
            // XXX should check for a possible clobber from in-memory data
354
            if (!writing) {
359
            if (!writing) {
355
                loaded = false;
360
                loaded = false;
356
            }
361
            }
357
            fireChange();
362
            fireChange(ev);
358
            if (!writing) {
363
            if (!writing) {
359
                helper.fireExternalChange(path);
364
                helper.fireExternalChange(path);
360
            }
365
            }
361
        }
366
        }
362
367
363
        public void fileCreated(FileChangeSupportEvent event) {
368
        public void fileCreated(FileChangeSupportEvent event) {
364
            diskChange();
369
            diskChange(event);
365
        }
370
        }
366
371
367
        public void fileDeleted(FileChangeSupportEvent event) {
372
        public void fileDeleted(FileChangeSupportEvent event) {
368
            diskChange();
373
            diskChange(event);
369
        }
374
        }
370
375
371
        public void fileModified(FileChangeSupportEvent event) {
376
        public void fileModified(FileChangeSupportEvent event) {
372
            diskChange();
377
            diskChange(event);
373
        }
378
        }
374
        
379
        
375
    }
380
    }
(-)a/project.ant/src/org/netbeans/spi/project/support/ant/PropertyUtils.java (-11 / +1 lines)
Lines 175-191 Link Here
175
                                return null;
175
                                return null;
176
                            }
176
                            }
177
                        }
177
                        }
178
                        FileLock lock = bp.lock();
178
                        properties.store(bp);
179
                        try {
180
                            OutputStream os = bp.getOutputStream(lock);
181
                            try {
182
                                properties.store(os);
183
                            } finally {
184
                                os.close();
185
                            }
186
                        } finally {
187
                            lock.releaseLock();
188
                        }
189
                    } else {
179
                    } else {
190
                        throw new IOException("Do not know where to store build.properties; must set netbeans.user!"); // NOI18N
180
                        throw new IOException("Do not know where to store build.properties; must set netbeans.user!"); // NOI18N
191
                    }
181
                    }
(-)a/project.ant/test/unit/src/org/netbeans/modules/project/ant/FileChangeSupportTest.java (+59 lines)
Lines 48-60 Link Here
48
48
49
import java.io.File;
49
import java.io.File;
50
import java.io.FileOutputStream;
50
import java.io.FileOutputStream;
51
import java.io.IOException;
52
import java.io.InterruptedIOException;
51
import java.util.ArrayList;
53
import java.util.ArrayList;
52
import java.util.Collections;
54
import java.util.Collections;
53
import java.util.List;
55
import java.util.List;
56
import junit.framework.Test;
54
import org.netbeans.api.project.TestUtil;
57
import org.netbeans.api.project.TestUtil;
55
import org.netbeans.junit.NbTestCase;
58
import org.netbeans.junit.NbTestCase;
59
import org.netbeans.junit.NbTestSuite;
56
import org.openide.filesystems.FileObject;
60
import org.openide.filesystems.FileObject;
61
import org.openide.filesystems.FileSystem.AtomicAction;
57
import org.openide.filesystems.FileUtil;
62
import org.openide.filesystems.FileUtil;
63
import org.openide.util.Exceptions;
58
64
59
/**
65
/**
60
 * Test {@link FileChangeSupport}.
66
 * Test {@link FileChangeSupport}.
Lines 76-82 Link Here
76
    
82
    
77
    private FileObject scratch;
83
    private FileObject scratch;
78
    private String scratchPath;
84
    private String scratchPath;
85
86
87
    public static Test suite() {
88
        Test t = null;
89
//        t = new FileChangeSupportTest("testDirectNotifyChanges");
90
        if (t == null) {
91
            t = new NbTestSuite(FileChangeSupportTest.class);
92
        }
93
        return t;
94
    }
79
    
95
    
96
    @Override
80
    protected void setUp() throws Exception {
97
    protected void setUp() throws Exception {
81
        super.setUp();
98
        super.setUp();
82
        scratch = TestUtil.makeScratchDir(this);
99
        scratch = TestUtil.makeScratchDir(this);
Lines 152-157 Link Here
152
        scratch.getFileSystem().refresh(false);
169
        scratch.getFileSystem().refresh(false);
153
        assertEquals("and then a file deletion event", Collections.singletonList("D:" + fileF), l.check());
170
        assertEquals("and then a file deletion event", Collections.singletonList("D:" + fileF), l.check());
154
    }
171
    }
172
173
    public void testDirectNotifyChanges() throws Exception {
174
        doDirectChanges();
175
    }
176
177
    public void testDirectNotifyChangesInAtomicAction() throws Exception {
178
        scratch.getFileSystem().runAtomicAction(new AtomicAction() {
179
            public void run() throws IOException {
180
                doDirectChanges();
181
            }
182
        });
183
    }
184
185
186
    private void doDirectChanges() throws IOException {
187
        File fileF = new File(scratchPath + SEP + "dir" + SEP + "file2");
188
        L l = new L();
189
        FileChangeSupport.DEFAULT.addListener(l, fileF);
190
        File dirF = new File(scratchPath + SEP + "dir");
191
        dirF.mkdir();
192
        new FileOutputStream(fileF).close();
193
        FileChangeSupport.DEFAULT.notifyChange(fileF);
194
        assertEquals("got file creation event", Collections.singletonList("M:" + fileF), l.check());
195
        scratch.getFileSystem().refresh(false);
196
        assertEquals("no new file creation event", Collections.emptyList(), l.check());
197
        try {
198
            Thread.sleep(SLEEP); // make sure timestamp changes
199
        } catch (InterruptedException ex) {
200
            throw new InterruptedIOException(ex.getMessage());
201
        }
202
        new FileOutputStream(fileF).close();
203
        FileChangeSupport.DEFAULT.notifyChange(fileF);
204
        assertEquals("and then a mod in file", Collections.singletonList("M:" + fileF), l.check());
205
        scratch.getFileSystem().refresh(false);
206
        assertEquals("no new file mod event", Collections.emptyList(), l.check());
207
        fileF.delete();
208
        dirF.delete();
209
        FileChangeSupport.DEFAULT.notifyChange(fileF);
210
        assertEquals("and then a file deletion event", Collections.singletonList("D:" + fileF), l.check());
211
        scratch.getFileSystem().refresh(false);
212
        assertEquals("no new file del w file mod event", Collections.emptyList(), l.check());
213
    }
155
    
214
    
156
    public void test66444() throws Exception {
215
    public void test66444() throws Exception {
157
        File fileF = new File(scratchPath + SEP + "dir" + SEP + "file2");
216
        File fileF = new File(scratchPath + SEP + "dir" + SEP + "file2");
(-)a/project.ant/test/unit/src/org/netbeans/modules/project/ant/ProjectLibraryProviderTest.java (-3 / +1 lines)
Lines 391-399 Link Here
391
            String[] nameValue = def.split("=", 2);
391
            String[] nameValue = def.split("=", 2);
392
            ep.put(nameValue[0], nameValue[1]);
392
            ep.put(nameValue[0], nameValue[1]);
393
        }
393
        }
394
        OutputStream os = f.getOutputStream();
394
        ep.store(f);
395
        ep.store(os);
396
        os.close();
397
    }
395
    }
398
396
399
    private static void storeDefs(Project project, String... definitions) throws IOException {
397
    private static void storeDefs(Project project, String... definitions) throws IOException {
(-)a/project.ant/test/unit/src/org/netbeans/spi/project/support/ant/EditablePropertiesTest.java (+58 lines)
Lines 59-64 Link Here
59
import java.util.Iterator;
59
import java.util.Iterator;
60
import java.util.Map;
60
import java.util.Map;
61
import org.netbeans.junit.NbTestCase;
61
import org.netbeans.junit.NbTestCase;
62
import org.netbeans.modules.project.ant.FileChangeSupport;
63
import org.netbeans.modules.project.ant.FileChangeSupportEvent;
64
import org.netbeans.modules.project.ant.FileChangeSupportListener;
65
import org.openide.filesystems.FileChangeAdapter;
66
import org.openide.filesystems.FileEvent;
67
import org.openide.filesystems.FileObject;
68
import org.openide.filesystems.FileSystem.AtomicAction;
69
import org.openide.filesystems.FileUtil;
62
70
63
public class EditablePropertiesTest extends NbTestCase {
71
public class EditablePropertiesTest extends NbTestCase {
64
72
Lines 121-126 Link Here
121
        String dest = getWorkDirPath()+File.separatorChar+"new.properties";
129
        String dest = getWorkDirPath()+File.separatorChar+"new.properties";
122
        saveProperties(ep, dest);
130
        saveProperties(ep, dest);
123
        assertFile("Saved properties must be the same as original one", filenameOfTestProperties(), dest, (String)null);
131
        assertFile("Saved properties must be the same as original one", filenameOfTestProperties(), dest, (String)null);
132
    }
133
134
    public void testSaveToFileObject() throws Exception {
135
        doSaveToFileObject();
136
    }
137
138
    public void testSaveToFileObjectInAtomic() throws Exception {
139
        final Add[] ret = new Add[1];
140
141
        FileUtil.runAtomicAction(new AtomicAction() {
142
            public void run() throws IOException {
143
                ret[0] = doSaveToFileObject();
144
            }
145
        });
146
147
        assertEquals("No additional events delivered after atomic action", 1, ret[0].cnt);
148
    }
149
    private static class Add implements FileChangeSupportListener {
150
        int cnt;
151
152
        public void fileCreated(FileChangeSupportEvent event) {
153
            fail();
154
        }
155
156
        public void fileDeleted(FileChangeSupportEvent event) {
157
            fail();
158
        }
159
160
        public void fileModified(FileChangeSupportEvent event) {
161
            cnt++;
162
        }
163
    }
164
165
    private Add doSaveToFileObject() throws IOException {
166
        clearWorkDir();
167
        EditableProperties ep = loadTestProperties();
168
        FileObject some = FileUtil.toFileObject(getWorkDir()).createData("p.properties");
169
        some.refresh();
170
171
        File destFile = FileUtil.toFile(some);
172
        String dest = destFile.getPath();
173
174
        Add listener = new Add();
175
        FileChangeSupport.DEFAULT.addListener(listener, destFile);
176
177
        ep.store(some);
178
        assertFile("Saved properties must be the same as original one", filenameOfTestProperties(), dest, (String)null);
179
        assertEquals("One change notified", 1, listener.cnt);
180
181
        return listener;
124
    }
182
    }
125
    
183
    
126
    public void testClonability() throws Exception {
184
    public void testClonability() throws Exception {
(-)a/project.ant/test/unit/src/org/netbeans/spi/project/support/ant/ReferenceHelperTest.java (-12 / +2 lines)
Lines 979-996 Link Here
979
	for (int cntr = 0; cntr < keys.length; cntr++) {
979
	for (int cntr = 0; cntr < keys.length; cntr++) {
980
	    p.setProperty(keys[cntr], values[cntr]);
980
	    p.setProperty(keys[cntr], values[cntr]);
981
	}
981
	}
982
	
982
983
	FileLock lock = prop.lock();
983
    p.store(prop);
984
	try {
985
	    OutputStream os = prop.getOutputStream(lock);
986
	    try {
987
		p.store(os);
988
	    } finally {
989
		os.close();
990
	    }
991
	} finally {
992
	    lock.releaseLock();
993
	}
994
    }
984
    }
995
    
985
    
996
    public void testFixReferences() throws Exception {
986
    public void testFixReferences() throws Exception {
(-)a/projectapi/apichanges.xml (+19 lines)
Lines 105-110 Link Here
105
105
106
    <changes>
106
    <changes>
107
107
108
        <change id="fs-events">
109
            <api name="general"/>
110
            <summary><code>FileSystem.AtomicAction</code> interaction</summary>
111
            <version major="1" minor="20"/>
112
            <date day="15" month="9" year="2008"/>
113
            <author login="mkubec"/>
114
            <compatibility addition="yes" binary="compatible" deletion="no" deprecation="no" modification="no" semantic="compatible" source="compatible"/>
115
            <description>
116
                <p>
117
                Ability to recognize events generated by
118
                code running inside <code>ProjectManager.mutex()</code> is
119
                now provided by 
120
                <a href="@TOP@/org/netbeans/api/project/ProjectManager.html#isMutexEvent(org.openide.filesystems.FileEvent)">isMutexEvent</a>
121
                method.
122
                </p>
123
            </description>
124
            <class package="org.netbeans.api.project" name="ProjectManager"/>
125
            <issue number="146072"/>
126
        </change>
108
        <change id="test-single-method">
127
        <change id="test-single-method">
109
            <api name="general"/>
128
            <api name="general"/>
110
            <summary>Added class <code>SingleMethod</code></summary>
129
            <summary>Added class <code>SingleMethod</code></summary>
(-)a/projectapi/manifest.mf (-1 / +1 lines)
Lines 1-7 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.projectapi/1
2
OpenIDE-Module: org.netbeans.modules.projectapi/1
3
OpenIDE-Module-Install: org/netbeans/modules/projectapi/Installer.class
3
OpenIDE-Module-Install: org/netbeans/modules/projectapi/Installer.class
4
OpenIDE-Module-Specification-Version: 1.19
4
OpenIDE-Module-Specification-Version: 1.20
5
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/projectapi/Bundle.properties
5
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/projectapi/Bundle.properties
6
OpenIDE-Module-Layer: org/netbeans/modules/projectapi/layer.xml
6
OpenIDE-Module-Layer: org/netbeans/modules/projectapi/layer.xml
7
7
(-)a/projectapi/src/org/netbeans/api/project/ProjectManager.java (-9 / +47 lines)
Lines 54-59 Link Here
54
import java.util.logging.Level;
54
import java.util.logging.Level;
55
import java.util.logging.LogRecord;
55
import java.util.logging.LogRecord;
56
import java.util.logging.Logger;
56
import java.util.logging.Logger;
57
import org.netbeans.api.queries.FileEncodingQuery;
57
import org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation;
58
import org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation;
58
import org.netbeans.modules.projectapi.TimedWeakReference;
59
import org.netbeans.modules.projectapi.TimedWeakReference;
59
import org.netbeans.spi.project.FileOwnerQueryImplementation;
60
import org.netbeans.spi.project.FileOwnerQueryImplementation;
Lines 112-130 Link Here
112
        return DEFAULT;
113
        return DEFAULT;
113
    }
114
    }
114
    
115
    
115
    private static final Executor FS_EXEC = new Executor() {
116
    private static final PostCommand FS_EXEC = new PostCommand();
116
        public void execute(final Runnable command) {
117
118
    private static class PostCommand implements Executor, FileSystem.AtomicAction {
119
        private Runnable run;
120
121
        public void execute(Runnable run) {
122
            PostCommand p = new PostCommand();
123
            p.run = run;
117
            try {
124
            try {
118
                FileUtil.runAtomicAction(new FileSystem.AtomicAction() {
125
                FileUtil.runAtomicAction(p);
119
                    public void run() throws IOException {
120
                        command.run();
121
                    }
122
                });
123
            } catch (IOException ex) {
126
            } catch (IOException ex) {
124
                throw (IllegalStateException) new IllegalStateException().initCause(ex);
127
                throw (IllegalStateException) new IllegalStateException().initCause(ex);
125
            }
128
            }
126
        }
129
        }
127
    };
130
131
        public void run() throws IOException {
132
            run.run();
133
        }
134
135
        @Override
136
        public int hashCode() {
137
            return getClass().hashCode();
138
        }
139
140
        @Override
141
        public boolean equals(Object obj) {
142
            if (obj == null) {
143
                return false;
144
            }
145
            return obj.getClass().equals(getClass());
146
        }
147
    }
128
148
129
    private static final Mutex MUTEX = new Mutex(new Mutex.Privileged(), FS_EXEC);
149
    private static final Mutex MUTEX = new Mutex(new Mutex.Privileged(), FS_EXEC);
130
    
150
    
Lines 143-149 Link Here
143
    public static Mutex mutex() {
163
    public static Mutex mutex() {
144
        return MUTEX;
164
        return MUTEX;
145
    }
165
    }
146
    
166
167
    /** Can distinguish events generated under the {@link #mutex()} lock from
168
     * those genereated without holding the lock.
169
     * The code running under the {@link #mutex()} can access filesystems and
170
     * generate {@link FileEvent} changes. However as this code is running inside
171
     * {@link FileUtil#runAtomicAction(org.openide.filesystems.FileSystem.AtomicAction)}
172
     * block, these events are delivered with a delay. Still, for some purposes,
173
     * it may be useful to distinguish the events from inside the {@link #mutex()}
174
     * from the others. This method does that.
175
     *
176
     * @param ev a filesystem event
177
     * @return true if and only if it has been generated by a code running with {@link #mutex()} access
178
     * @since 1.20
179
     */
180
    public static boolean isMutexEvent(FileEvent ev) {
181
        return ev.firedFrom(FS_EXEC);
182
    }
183
184
147
    private static enum LoadStatus {
185
    private static enum LoadStatus {
148
        /**
186
        /**
149
         * Marker for a directory which is known to not be a project.
187
         * Marker for a directory which is known to not be a project.

Return to bug 146072