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 124980
Collapse All | Expand All

(-)projects/projectui/src/org/netbeans/modules/project/ui/OpenProjectList.java (-2 / +94 lines)
Lines 68-73 Link Here
68
import java.util.Queue;
68
import java.util.Queue;
69
import java.util.Set;
69
import java.util.Set;
70
import java.util.StringTokenizer;
70
import java.util.StringTokenizer;
71
import java.util.concurrent.ExecutionException;
72
import java.util.concurrent.Future;
73
import java.util.concurrent.Semaphore;
74
import java.util.concurrent.TimeUnit;
75
import java.util.concurrent.TimeoutException;
76
import java.util.concurrent.locks.Condition;
77
import java.util.concurrent.locks.Lock;
78
import java.util.concurrent.locks.ReentrantLock;
71
import java.util.logging.Level;
79
import java.util.logging.Level;
72
import java.util.logging.LogRecord;
80
import java.util.logging.LogRecord;
73
import java.util.logging.Logger;
81
import java.util.logging.Logger;
Lines 199-206 Link Here
199
        }
207
        }
200
    }
208
    }
201
    
209
    
210
    Future<Project[]> openProjectsAPI() {
211
        return LOAD;
212
    }
202
    
213
    
203
    private final class LoadOpenProjects implements Runnable, LookupListener {
214
    
215
    private final class LoadOpenProjects implements Runnable, LookupListener, Future<Project[]> {
204
        final RequestProcessor RP = new RequestProcessor("Load Open Projects"); // NOI18N
216
        final RequestProcessor RP = new RequestProcessor("Load Open Projects"); // NOI18N
205
        final RequestProcessor.Task TASK = RP.create(this);
217
        final RequestProcessor.Task TASK = RP.create(this);
206
        private int action;
218
        private int action;
Lines 209-214 Link Here
209
        private List<String> recentTemplates;
221
        private List<String> recentTemplates;
210
        private Project mainProject;
222
        private Project mainProject;
211
        private Lookup.Result<FileObject> currentFiles;
223
        private Lookup.Result<FileObject> currentFiles;
224
        private int entered;
225
        private final Lock enteredGuard = new ReentrantLock();
226
        private final Condition enteredZeroed = enteredGuard.newCondition();
212
        
227
        
213
        public LoadOpenProjects(int a) {
228
        public LoadOpenProjects(int a) {
214
            action = a;
229
            action = a;
Lines 321-328 Link Here
321
            }
336
            }
322
337
323
        }
338
        }
339
340
        final void enter() {
341
            try {
342
                enteredGuard.lock();
343
                entered++;
344
            } finally {
345
                enteredGuard.unlock();
324
    }
346
    }
347
        }
325
    
348
    
349
        final void exit() {
350
            try {
351
                enteredGuard.lock();
352
                if (--entered == 0) {
353
                    enteredZeroed.signalAll();
354
                }
355
            } finally {
356
                enteredGuard.unlock();
357
            }
358
            
359
        }
360
        
361
362
        public boolean cancel(boolean mayInterruptIfRunning) {
363
            return false;
364
        }
365
366
        public boolean isCancelled() {
367
            return false;
368
        }
369
370
        public boolean isDone() {
371
            return TASK.isFinished() && entered == 0;
372
        }
373
374
        public Project[] get() throws InterruptedException, ExecutionException {
375
            TASK.waitFinished();
376
            try {
377
                enteredGuard.lock();
378
                while (entered > 0) {
379
                    enteredZeroed.await();
380
                }
381
            } finally {
382
                enteredGuard.unlock();
383
            }
384
            return getDefault().getOpenProjects();
385
        }
386
387
        public Project[] get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
388
            long ms = unit.convert(timeout, TimeUnit.MILLISECONDS);
389
            if (!TASK.waitFinished(timeout)) {
390
                throw new TimeoutException();
391
            } 
392
            try {
393
                enteredGuard.lock();
394
                if (entered > 0) {
395
                    if (!enteredZeroed.await(ms, TimeUnit.MILLISECONDS)) {
396
                        throw new TimeoutException();
397
                    }
398
                }
399
            } finally {
400
                enteredGuard.unlock();
401
            }
402
            return getDefault().getOpenProjects();
403
        }
404
    }
405
    
326
    public void open( Project p ) {
406
    public void open( Project p ) {
327
        open( new Project[] {p}, false );
407
        open( new Project[] {p}, false );
328
    }
408
    }
Lines 407-412 Link Here
407
        assert !Arrays.asList(projects).contains(null) : "Projects can't be null";
487
        assert !Arrays.asList(projects).contains(null) : "Projects can't be null";
408
        LOAD.waitFinished();
488
        LOAD.waitFinished();
409
            
489
            
490
            
491
        try {
492
            LOAD.enter();
410
        boolean recentProjectsChanged = false;
493
        boolean recentProjectsChanged = false;
411
        int  maxWork = 1000;
494
        int  maxWork = 1000;
412
        int  workForSubprojects = maxWork / 2;
495
        int  workForSubprojects = maxWork / 2;
Lines 502-508 Link Here
502
        LogRecord[] addedRec = createRecord("UI_OPEN_PROJECTS", projectsToOpen.toArray(new Project[0])); // NOI18N
585
        LogRecord[] addedRec = createRecord("UI_OPEN_PROJECTS", projectsToOpen.toArray(new Project[0])); // NOI18N
503
        log(addedRec);
586
        log(addedRec);
504
        
587
        
505
        
506
        Mutex.EVENT.readAccess(new Action<Void>() {
588
        Mutex.EVENT.readAccess(new Action<Void>() {
507
            public Void run() {
589
            public Void run() {
508
                pchSupport.firePropertyChange( PROPERTY_OPEN_PROJECTS, oldprjs.toArray(new Project[oldprjs.size()]), 
590
                pchSupport.firePropertyChange( PROPERTY_OPEN_PROJECTS, oldprjs.toArray(new Project[oldprjs.size()]), 
Lines 514-526 Link Here
514
                return null;
596
                return null;
515
            }
597
            }
516
        });
598
        });
599
        } finally {
600
            LOAD.exit();
517
    }
601
    }
602
    }
518
       
603
       
519
    public void close( Project projects[], boolean notifyUI ) {
604
    public void close( Project projects[], boolean notifyUI ) {
520
        LOAD.waitFinished();
605
        LOAD.waitFinished();
521
        if (!ProjectUtilities.closeAllDocuments (projects, notifyUI )) {
606
        if (!ProjectUtilities.closeAllDocuments (projects, notifyUI )) {
522
            return;
607
            return;
523
        }
608
        }
609
        
610
        try {
611
            LOAD.enter();
612
524
        logProjects("close(): closing project: ", projects);
613
        logProjects("close(): closing project: ", projects);
525
        boolean mainClosed = false;
614
        boolean mainClosed = false;
526
        boolean someClosed = false;
615
        boolean someClosed = false;
Lines 577-583 Link Here
577
        }
666
        }
578
        LogRecord[] removedRec = createRecord("UI_CLOSED_PROJECTS", projects); // NOI18N
667
        LogRecord[] removedRec = createRecord("UI_CLOSED_PROJECTS", projects); // NOI18N
579
        log(removedRec);
668
        log(removedRec);
669
        } finally {
670
            LOAD.exit();
580
    }
671
    }
672
    }
581
        
673
        
582
    public synchronized Project[] getOpenProjects() {
674
    public synchronized Project[] getOpenProjects() {
583
        Project projects[] = new Project[ openProjects.size() ];
675
        Project projects[] = new Project[ openProjects.size() ];
(-)projects/projectui/src/org/netbeans/modules/project/ui/OpenProjectsTrampolineImpl.java (+5 lines)
Lines 44-49 Link Here
44
import java.beans.PropertyChangeEvent;
44
import java.beans.PropertyChangeEvent;
45
import java.beans.PropertyChangeListener;
45
import java.beans.PropertyChangeListener;
46
import java.beans.PropertyChangeSupport;
46
import java.beans.PropertyChangeSupport;
47
import java.util.concurrent.Future;
47
import org.netbeans.api.project.Project;
48
import org.netbeans.api.project.Project;
48
import org.netbeans.api.project.ui.OpenProjects;
49
import org.netbeans.api.project.ui.OpenProjects;
49
import org.netbeans.modules.project.uiapi.OpenProjectsTrampoline;
50
import org.netbeans.modules.project.uiapi.OpenProjectsTrampoline;
Lines 118-121 Link Here
118
        OpenProjectList.getDefault().setMainProject(project);
119
        OpenProjectList.getDefault().setMainProject(project);
119
    }
120
    }
120
    
121
    
122
    public Future<Project[]> openProjectsAPI() {
123
        return OpenProjectList.getDefault().openProjectsAPI();
121
}
124
}
125
    
126
}
(-)projects/projectui/test/unit/src/org/netbeans/modules/project/ui/OpenProjectListTest.java (-1 / +23 lines)
Lines 54-65 Link Here
54
import java.util.Set;
54
import java.util.Set;
55
import java.util.SortedSet;
55
import java.util.SortedSet;
56
import java.util.TreeSet;
56
import java.util.TreeSet;
57
import java.util.concurrent.TimeUnit;
58
import java.util.concurrent.TimeoutException;
57
import java.util.logging.Level;
59
import java.util.logging.Level;
58
import java.util.regex.Matcher;
60
import java.util.regex.Matcher;
59
import java.util.regex.Pattern;
61
import java.util.regex.Pattern;
60
import org.netbeans.api.project.FileOwnerQuery;
62
import org.netbeans.api.project.FileOwnerQuery;
61
import org.netbeans.api.project.Project;
63
import org.netbeans.api.project.Project;
62
import org.netbeans.api.project.ProjectManager;
64
import org.netbeans.api.project.ProjectManager;
65
import org.netbeans.api.project.ui.OpenProjects;
63
import org.netbeans.junit.Log;
66
import org.netbeans.junit.Log;
64
import org.netbeans.junit.MockServices;
67
import org.netbeans.junit.MockServices;
65
import org.netbeans.junit.NbTestCase;
68
import org.netbeans.junit.NbTestCase;
Lines 72-77 Link Here
72
import org.openide.filesystems.URLMapper;
75
import org.openide.filesystems.URLMapper;
73
import org.openide.loaders.DataObject;
76
import org.openide.loaders.DataObject;
74
import org.openide.loaders.DataObjectNotFoundException;
77
import org.openide.loaders.DataObjectNotFoundException;
78
import org.openide.util.RequestProcessor;
75
import org.openide.util.lookup.Lookups;
79
import org.openide.util.lookup.Lookups;
76
80
77
/** Tests fix of issue 56454.
81
/** Tests fix of issue 56454.
Lines 436-455 Link Here
436
        }
440
        }
437
    }
441
    }
438
    
442
    
439
    private static class TestProjectOpenedHookImpl extends ProjectOpenedHook {
443
    private static class TestProjectOpenedHookImpl extends ProjectOpenedHook 
444
    implements Runnable {
440
        
445
        
441
        public static int opened = 0;
446
        public static int opened = 0;
442
        public static int closed = 0;
447
        public static int closed = 0;
443
        
448
        
449
        private Object result;
450
        
444
        protected void projectClosed() {
451
        protected void projectClosed() {
445
            closed++;
452
            closed++;
453
            assertFalse("Working on", OpenProjects.getDefault().openProjects().isDone());
454
            RequestProcessor.getDefault().post(this).waitFinished();
455
            assertNotNull("some result computed", result);
456
            assertEquals("It is time out exception", TimeoutException.class, result.getClass());
446
        }
457
        }
447
        
458
        
448
        protected void projectOpened() {
459
        protected void projectOpened() {
449
            opened++;
460
            opened++;
461
            assertFalse("Working on", OpenProjects.getDefault().openProjects().isDone());
462
            RequestProcessor.getDefault().post(this).waitFinished();
463
            assertNotNull("some result computed", result);
464
            assertEquals("It is time out exception", TimeoutException.class, result.getClass());
450
        }
465
        }
451
        
466
        
467
        public void run() {
468
            try {
469
                result = OpenProjects.getDefault().openProjects().get(100, TimeUnit.MILLISECONDS);
470
            } catch (Exception ex) {
471
                result = ex;
452
    }
472
    }
473
        }
474
    }
453
    
475
    
454
    private class ChangeListener implements PropertyChangeListener {
476
    private class ChangeListener implements PropertyChangeListener {
455
        int oldCount = -1;
477
        int oldCount = -1;
(-)projects/projectui/test/unit/src/org/netbeans/modules/project/ui/ProjectsRootNodeTest.java (-2 / +30 lines)
Lines 46-54 Link Here
46
import java.util.EventObject;
46
import java.util.EventObject;
47
import java.util.List;
47
import java.util.List;
48
import java.util.concurrent.CountDownLatch;
48
import java.util.concurrent.CountDownLatch;
49
import java.util.concurrent.ExecutionException;
50
import java.util.concurrent.TimeUnit;
51
import java.util.concurrent.TimeoutException;
49
import javax.swing.Action;
52
import javax.swing.Action;
50
import junit.framework.TestCase;
53
import junit.framework.TestCase;
54
import org.netbeans.api.project.Project;
51
import org.netbeans.api.project.ProjectManager;
55
import org.netbeans.api.project.ProjectManager;
56
import org.netbeans.api.project.ui.OpenProjects;
52
import org.netbeans.junit.MockServices;
57
import org.netbeans.junit.MockServices;
53
import org.netbeans.junit.NbTestCase;
58
import org.netbeans.junit.NbTestCase;
54
import org.netbeans.modules.project.ui.actions.TestSupport;
59
import org.netbeans.modules.project.ui.actions.TestSupport;
Lines 63-68 Link Here
63
import org.openide.nodes.NodeMemberEvent;
68
import org.openide.nodes.NodeMemberEvent;
64
import org.openide.nodes.NodeReorderEvent;
69
import org.openide.nodes.NodeReorderEvent;
65
import org.openide.util.Exceptions;
70
import org.openide.util.Exceptions;
71
import org.openide.util.RequestProcessor;
66
import org.openide.util.lookup.Lookups;
72
import org.openide.util.lookup.Lookups;
67
73
68
/** 
74
/** 
Lines 111-117 Link Here
111
        super.tearDown();
117
        super.tearDown();
112
    }
118
    }
113
119
114
    public void testBehaviourOfProjectsLogicNode() throws InterruptedException {
120
    public void testBehaviourOfProjectsLogicNode() throws Exception {
115
        Node logicalView = new ProjectsRootNode(ProjectsRootNode.LOGICAL_VIEW);
121
        Node logicalView = new ProjectsRootNode(ProjectsRootNode.LOGICAL_VIEW);
116
        L listener = new L();
122
        L listener = new L();
117
        logicalView.addNodeListener(listener);
123
        logicalView.addNodeListener(listener);
Lines 139-144 Link Here
139
        }
145
        }
140
        
146
        
141
        listener.assertEvents("Goal is to receive no events at all", 0);
147
        listener.assertEvents("Goal is to receive no events at all", 0);
148
        assertTrue("Finished", OpenProjects.getDefault().openProjects().isDone());
149
        assertFalse("Not cancelled, Finished", OpenProjects.getDefault().openProjects().isCancelled());
150
        Project[] arr = OpenProjects.getDefault().openProjects().get();
151
        assertEquals("30", 30, arr.length);
142
    }
152
    }
143
    
153
    
144
    private static class L implements NodeListener {
154
    private static class L implements NodeListener {
Lines 176-182 Link Here
176
        
186
        
177
    }
187
    }
178
    
188
    
179
    private static class TestProjectOpenedHookImpl extends ProjectOpenedHook {
189
    private static class TestProjectOpenedHookImpl extends ProjectOpenedHook 
190
    implements Runnable {
180
        
191
        
181
        public static CountDownLatch toOpen = new CountDownLatch(30);
192
        public static CountDownLatch toOpen = new CountDownLatch(30);
182
        public static int opened = 0;
193
        public static int opened = 0;
Lines 193-199 Link Here
193
            closed++;
204
            closed++;
194
        }
205
        }
195
        
206
        
207
        Project[] arr;
208
        public void run() {
209
            try {
210
                arr = OpenProjects.getDefault().openProjects().get(50, TimeUnit.MILLISECONDS);
211
            } catch (InterruptedException ex) {
212
                fail("Wrong exception");
213
            } catch (ExecutionException ex) {
214
                fail("Wrong exception");
215
            } catch (TimeoutException ex) {
216
                // OK
217
            }
218
        }
219
        
196
        protected void projectOpened() {
220
        protected void projectOpened() {
221
            assertFalse("Running", OpenProjects.getDefault().openProjects().isDone());
222
            // now verify that other threads do not see results from the Future
223
            RequestProcessor.getDefault().post(this).waitFinished();
224
            assertNull("TimeoutException thrown", arr);
197
            if (toWaitOn != null) {
225
            if (toWaitOn != null) {
198
                try {
226
                try {
199
                    toWaitOn.await();
227
                    toWaitOn.await();
(-)projects/projectuiapi/apichanges.xml (+18 lines)
Lines 105-110 Link Here
105
105
106
    <changes>
106
    <changes>
107
        
107
        
108
        <change id="observe-opening-closing">
109
            <api name="general"/>
110
            <summary>Added ways to track projects opening and closing</summary>
111
            <version major="1" minor="27"/>
112
            <date day="30" month="1" 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
                Added a method to track progress of projects opening and closing. As the
117
                opening of a project may take long time, and as there can be multiple
118
                projects open at once, it may be necessary to be notified that the process
119
                of open project list modification started or that it has
120
                finished.
121
            </description>
122
            <class package="org.netbeans.api.project.ui" name="OpenProjects"/>
123
            <issue number="124980"/>
124
        </change>
125
        
108
        <change id="store-listener-added">
126
        <change id="store-listener-added">
109
            <api name="general"/>
127
            <api name="general"/>
110
            <summary>Added methods for creating customizer UI with additional listener for saving outside of AWT EQ</summary>
128
            <summary>Added methods for creating customizer UI with additional listener for saving outside of AWT EQ</summary>
(-)projects/projectuiapi/nbproject/project.properties (-1 / +1 lines)
Lines 39-45 Link Here
39
39
40
javac.compilerargs=-Xlint -Xlint:-serial
40
javac.compilerargs=-Xlint -Xlint:-serial
41
javac.source=1.5
41
javac.source=1.5
42
spec.version.base=1.26.0
42
spec.version.base=1.27.0
43
is.autoload=true
43
is.autoload=true
44
javadoc.arch=${basedir}/arch.xml
44
javadoc.arch=${basedir}/arch.xml
45
javadoc.apichanges=${basedir}/apichanges.xml
45
javadoc.apichanges=${basedir}/apichanges.xml
(-)projects/projectuiapi/src/org/netbeans/api/project/ui/OpenProjects.java (+31 lines)
Lines 42-47 Link Here
42
package org.netbeans.api.project.ui;
42
package org.netbeans.api.project.ui;
43
43
44
import java.beans.PropertyChangeListener;
44
import java.beans.PropertyChangeListener;
45
import java.util.concurrent.Future;
45
import org.netbeans.api.project.Project;
46
import org.netbeans.api.project.Project;
46
import org.netbeans.modules.project.uiapi.OpenProjectsTrampoline;
47
import org.netbeans.modules.project.uiapi.OpenProjectsTrampoline;
47
import org.netbeans.modules.project.uiapi.Utilities;
48
import org.netbeans.modules.project.uiapi.Utilities;
Lines 114-119 Link Here
114
    }
115
    }
115
116
116
    /**
117
    /**
118
     * Method to track progress of projects opening and closing. As the
119
     * opening of a project may take long time, and as there can be multiple
120
     * projects open at once, it may be necessary to be notified that the process
121
     * of open project list modification started or that it has
122
     * finished. This method provides a <q>future</q> that can do that.
123
     * To find out that the list of open projects is currently modified use:
124
     * <pre>
125
     * assert openProjects().isDone() == false;
126
     * </pre>
127
     * To wait for the opening/closing to be finished and then obtain the result
128
     * use:
129
     * <pre>
130
     * Project[] current = openProjects().get();
131
     * </pre>
132
     * This result is different that a plain call to {@link #getOpenProjects} as
133
     * that methods returns the current state, whatever it is. While the call through
134
     * the <q>future</q> awaits for current modifications to finish. As such wait
135
     * can take a long time one can also wait for just a limited amount of time.
136
     * However this waiting methods should very likely only be used from dedicated threads,
137
     * where the wait does not block other essencial operations (read: do not
138
     * use such methods from AWT or other known threads!).
139
     * 
140
     * @return future to track computation of open projects
141
     * @since 1.27
142
     */
143
    public Future<Project[]> openProjects() {
144
        return trampoline.openProjectsAPI();
145
    }
146
147
    /**
117
     * Opens given projects.
148
     * Opens given projects.
118
     * Acquires {@link org.netbeans.api.project.ProjectManager#mutex()} in the write mode.
149
     * Acquires {@link org.netbeans.api.project.ProjectManager#mutex()} in the write mode.
119
     * @param projects to be opened. In the case when some of the projects are already opened
150
     * @param projects to be opened. In the case when some of the projects are already opened
(-)projects/projectuiapi/src/org/netbeans/modules/project/uiapi/OpenProjectsTrampoline.java (+3 lines)
Lines 42-47 Link Here
42
package org.netbeans.modules.project.uiapi;
42
package org.netbeans.modules.project.uiapi;
43
43
44
import java.beans.PropertyChangeListener;
44
import java.beans.PropertyChangeListener;
45
import java.util.concurrent.Future;
45
import org.netbeans.api.project.Project;
46
import org.netbeans.api.project.Project;
46
47
47
/**
48
/**
Lines 58-63 Link Here
58
59
59
    public void addPropertyChangeListenerAPI( PropertyChangeListener listener, Object source );
60
    public void addPropertyChangeListenerAPI( PropertyChangeListener listener, Object source );
60
61
62
    public Future<Project[]> openProjectsAPI();
63
61
    public void removePropertyChangeListenerAPI( PropertyChangeListener listener );
64
    public void removePropertyChangeListenerAPI( PropertyChangeListener listener );
62
    
65
    
63
    public Project getMainProject();
66
    public Project getMainProject();

Return to bug 124980