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

(-)a/hudson/src/org/netbeans/modules/hudson/api/HudsonFolder.java (+75 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2013 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.hudson.api;
44
45
import java.util.Collection;
46
import javax.swing.event.ChangeListener;
47
48
/**
49
 * An item which is a folder for other jobs (or subfolders).
50
 * Could be any {@code ViewGroup} but probably from the CloudBees Folders plugin for Jenkins.
51
 * <p>The current interface defines no {@code getViews} method, showing only the primary view.
52
 * This is not such a loss, since heavy users of folders are not likely to need lots of views anyway.
53
 * The standard connector also assumes that there is an exported {@link primaryView} field,
54
 * defined in the Jenkins version of the interface.
55
 * <p>In the Hudson/Jenkins model, this would really in an inheritance hierarchy with {@link HudsonJob} and {@link HudsonInstance},
56
 * but due to the many methods in those interfaces which make no sense on folders, it seems better to separate them.
57
 * @since XXX
58
 */
59
public interface HudsonFolder {
60
61
    String getName();
62
63
    String getUrl();
64
65
    Collection<HudsonJob> getJobs();
66
67
    Collection<HudsonFolder> getFolders();
68
69
    HudsonInstance getInstance();
70
71
    void addChangeListener(ChangeListener listener);
72
73
    void removeChangeListener(ChangeListener listener);
74
75
}
(-)a/hudson/src/org/netbeans/modules/hudson/api/HudsonInstance.java (+3 lines)
Lines 99-104 Link Here
99
     */
99
     */
100
    public Collection<HudsonJob> getJobs();
100
    public Collection<HudsonJob> getJobs();
101
101
102
    /** @since XXX */
103
    Collection<HudsonFolder> getFolders();
104
102
    /**
105
    /**
103
     * Returns all Hudson views from registered instance
106
     * Returns all Hudson views from registered instance
104
     *
107
     *
(-)a/hudson/src/org/netbeans/modules/hudson/impl/HudsonConnector.java (-12 / +47 lines)
Lines 63-68 Link Here
63
import java.util.regex.Pattern;
63
import java.util.regex.Pattern;
64
import org.netbeans.api.annotations.common.CheckForNull;
64
import org.netbeans.api.annotations.common.CheckForNull;
65
import org.netbeans.modules.hudson.api.ConnectionBuilder;
65
import org.netbeans.modules.hudson.api.ConnectionBuilder;
66
import org.netbeans.modules.hudson.api.HudsonFolder;
66
import org.netbeans.modules.hudson.api.HudsonJob;
67
import org.netbeans.modules.hudson.api.HudsonJob;
67
import org.netbeans.modules.hudson.api.HudsonJob.Color;
68
import org.netbeans.modules.hudson.api.HudsonJob.Color;
68
import org.netbeans.modules.hudson.api.HudsonJobBuild;
69
import org.netbeans.modules.hudson.api.HudsonJobBuild;
Lines 119-124 Link Here
119
        Document docInstance = getDocument(instanceUrl + XML_API_URL + (canUseTree(authentication) ?
120
        Document docInstance = getDocument(instanceUrl + XML_API_URL + (canUseTree(authentication) ?
120
                "?tree=primaryView[name],views[name,url,jobs[name]]," +
121
                "?tree=primaryView[name],views[name,url,jobs[name]]," +
121
                "jobs[name,url,color,displayName,buildable,inQueue," +
122
                "jobs[name,url,color,displayName,buildable,inQueue," +
123
                "primaryView," + // #215135: marker for folders
122
                "lastBuild[number],lastFailedBuild[number],lastStableBuild[number],lastSuccessfulBuild[number],lastCompletedBuild[number]," +
124
                "lastBuild[number],lastFailedBuild[number],lastStableBuild[number],lastSuccessfulBuild[number],lastCompletedBuild[number]," +
123
                "modules[name,displayName,url,color]]," +
125
                "modules[name,displayName,url,color]]," +
124
                "securedJobs[name,url]" : // HUDSON-3924
126
                "securedJobs[name,url]" : // HUDSON-3924
Lines 131-144 Link Here
131
        if (null == docInstance) {
133
        if (null == docInstance) {
132
            return new InstanceData(
134
            return new InstanceData(
133
                    Collections.<JobData>emptyList(),
135
                    Collections.<JobData>emptyList(),
134
                    Collections.<ViewData>emptyList());
136
                    Collections.<ViewData>emptyList(),
137
                    Collections.<FolderData>emptyList());
135
        }
138
        }
136
        // Clear cache
139
        // Clear cache
137
        cache.clear();
140
        cache.clear();
138
        // Parse jobs and return them
141
        // Parse jobs and return them
139
        Collection<ViewData> viewsData = getViewData(docInstance);
142
        Collection<ViewData> viewsData = getViewData(docInstance, instanceUrl);
140
        Collection<JobData> jobsData = getJobsData(docInstance, viewsData);
143
        Collection<FolderData> foldersData = new ArrayList<FolderData>();
141
        return new InstanceData(jobsData, viewsData);
144
        Collection<JobData> jobsData = getJobsData(docInstance, instanceUrl, viewsData, foldersData);
145
        return new InstanceData(jobsData, viewsData, foldersData);
146
    }
147
148
    @Override public InstanceData getInstanceData(HudsonFolder parentFolder, boolean authentication) {
149
        Document docInstance = getDocument(parentFolder.getUrl() + XML_API_URL + "?tree=jobs[name,url,color,displayName,buildable,inQueue,primaryView," +
150
                "lastBuild[number],lastFailedBuild[number],lastStableBuild[number],lastSuccessfulBuild[number],lastCompletedBuild[number]," +
151
                "modules[name,displayName,url,color]]," +
152
                "securedJobs[name,url]", authentication); // NOI18N
153
154
        if (null == docInstance) {
155
            return new InstanceData(
156
                    Collections.<JobData>emptyList(),
157
                    Collections.<ViewData>emptyList(),
158
                    Collections.<FolderData>emptyList());
159
        }
160
        // Clear cache
161
        cache.clear();
162
        Collection<FolderData> foldersData = new ArrayList<FolderData>();
163
        Collection<JobData> jobsData = getJobsData(docInstance, parentFolder.getUrl(), Collections.<ViewData>emptySet(), foldersData);
164
        return new InstanceData(jobsData, Collections.<ViewData>emptySet(), foldersData);
142
    }
165
    }
143
166
144
    @Override
167
    @Override
Lines 235-241 Link Here
235
        
258
        
236
    }
259
    }
237
    
260
    
238
    private Collection<ViewData> getViewData(Document doc) {
261
    private Collection<ViewData> getViewData(Document doc, String baseUrl) {
239
        String primaryViewName = null;
262
        String primaryViewName = null;
240
        Element primaryViewEl = XMLUtil.findElement(doc.getDocumentElement(), "primaryView", null); // NOI18N
263
        Element primaryViewEl = XMLUtil.findElement(doc.getDocumentElement(), "primaryView", null); // NOI18N
241
        if (primaryViewEl != null) {
264
        if (primaryViewEl != null) {
Lines 267-273 Link Here
267
                    name = o.getFirstChild().getTextContent();
290
                    name = o.getFirstChild().getTextContent();
268
                    isPrimary = name.equals(primaryViewName);
291
                    isPrimary = name.equals(primaryViewName);
269
                } else if (o.getNodeName().equals(XML_API_URL_ELEMENT)) {
292
                } else if (o.getNodeName().equals(XML_API_URL_ELEMENT)) {
270
                    url = normalizeUrl(o.getFirstChild().getTextContent(), isPrimary ? "" : "view/[^/]+/"); // NOI18N
293
                    url = normalizeUrl(baseUrl, o.getFirstChild().getTextContent(), isPrimary ? "" : "view/[^/]+/"); // NOI18N
271
                }
294
                }
272
            }
295
            }
273
            
296
            
Lines 300-307 Link Here
300
        return views;
323
        return views;
301
    }
324
    }
302
    
325
    
303
    private Collection<JobData> getJobsData(Document doc,
326
    private Collection<JobData> getJobsData(Document doc, String baseUrl,
304
            Collection<ViewData> viewsData) {
327
            Collection<ViewData> viewsData, Collection<FolderData> foldersData) {
305
        Collection<JobData> jobs = new ArrayList<JobData>();
328
        Collection<JobData> jobs = new ArrayList<JobData>();
306
        
329
        
307
        NodeList nodes = doc.getDocumentElement().getChildNodes();
330
        NodeList nodes = doc.getDocumentElement().getChildNodes();
Lines 314-319 Link Here
314
            
337
            
315
            JobData jd = new JobData();
338
            JobData jd = new JobData();
316
            jd.setSecured(secured);
339
            jd.setSecured(secured);
340
            FolderData fd = new FolderData();
341
            boolean isFolder = false;
317
            
342
            
318
            NodeList jobDetails = n.getChildNodes();
343
            NodeList jobDetails = n.getChildNodes();
319
            for (int k = 0; k < jobDetails.getLength(); k++) {
344
            for (int k = 0; k < jobDetails.getLength(); k++) {
Lines 324-331 Link Here
324
                String nodeName = d.getNodeName();
349
                String nodeName = d.getNodeName();
325
                if (nodeName.equals(XML_API_NAME_ELEMENT)) {
350
                if (nodeName.equals(XML_API_NAME_ELEMENT)) {
326
                    jd.setJobName(d.getFirstChild().getTextContent());
351
                    jd.setJobName(d.getFirstChild().getTextContent());
352
                    fd.setName(d.getFirstChild().getTextContent());
327
                } else if (nodeName.equals(XML_API_URL_ELEMENT)) {
353
                } else if (nodeName.equals(XML_API_URL_ELEMENT)) {
328
                    jd.setJobUrl(normalizeUrl(d.getFirstChild().getTextContent(), "job/[^/]+/")); // NOI18N
354
                    String u = normalizeUrl(baseUrl, d.getFirstChild().getTextContent(), "job/[^/]+/"); // NOI18N
355
                    jd.setJobUrl(u);
356
                    fd.setUrl(u);
357
                } else if (nodeName.equals("primaryView")) { // NOI18N
358
                    isFolder = true;
329
                } else if (nodeName.equals(XML_API_COLOR_ELEMENT)) {
359
                } else if (nodeName.equals(XML_API_COLOR_ELEMENT)) {
330
                    jd.setColor(Color.find(d.getFirstChild().getTextContent().trim()));
360
                    jd.setColor(Color.find(d.getFirstChild().getTextContent().trim()));
331
                } else if (nodeName.equals(XML_API_DISPLAY_NAME_ELEMENT)) {
361
                } else if (nodeName.equals(XML_API_DISPLAY_NAME_ELEMENT)) {
Lines 362-368 Link Here
362
                            } else if (nodeName2.equals("displayName")) { // NOI18N
392
                            } else if (nodeName2.equals("displayName")) { // NOI18N
363
                                displayName = text;
393
                                displayName = text;
364
                            } else if (nodeName2.equals("url")) { // NOI18N
394
                            } else if (nodeName2.equals("url")) { // NOI18N
365
                                url = normalizeUrl(text, "job/[^/]+/[^/]+/"); // NOI18N
395
                                url = normalizeUrl(baseUrl, text, "job/[^/]+/[^/]+/"); // NOI18N
366
                            } else if (nodeName2.equals("color")) { // NOI18N
396
                            } else if (nodeName2.equals("color")) { // NOI18N
367
                                color = Color.find(text);
397
                                color = Color.find(text);
368
                            } else {
398
                            } else {
Lines 391-397 Link Here
391
                    jd.addView(v.getName());
421
                    jd.addView(v.getName());
392
                }
422
                }
393
            }
423
            }
394
            jobs.add(jd);
424
            if (isFolder) {
425
                foldersData.add(fd);
426
            } else {
427
                jobs.add(jd);
428
            }
395
        }
429
        }
396
        return jobs;
430
        return jobs;
397
    }
431
    }
Lines 403-409 Link Here
403
     * @return analogous URL constructed from instance root, e.g. {@code https://my.facade/hudson/job/My%20Job/}
437
     * @return analogous URL constructed from instance root, e.g. {@code https://my.facade/hudson/job/My%20Job/}
404
     * @see "#165735"
438
     * @see "#165735"
405
     */
439
     */
406
    private String normalizeUrl(String suggested, String relativePattern) {
440
    private static String normalizeUrl(String instanceUrl, String suggested, String relativePattern) {
407
        Pattern tailPattern;
441
        Pattern tailPattern;
408
        synchronized (tailPatterns) {
442
        synchronized (tailPatterns) {
409
            tailPattern = tailPatterns.get(relativePattern);
443
            tailPattern = tailPatterns.get(relativePattern);
Lines 620-623 Link Here
620
        }
654
        }
621
        return items;
655
        return items;
622
    }
656
    }
657
623
}
658
}
(-)a/hudson/src/org/netbeans/modules/hudson/impl/HudsonFolderImpl.java (+131 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2013 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.hudson.impl;
44
45
import java.util.Collection;
46
import javax.swing.event.ChangeListener;
47
import org.netbeans.modules.hudson.api.HudsonChangeListener;
48
import org.netbeans.modules.hudson.api.HudsonFolder;
49
import org.netbeans.modules.hudson.api.HudsonInstance;
50
import org.netbeans.modules.hudson.api.HudsonJob;
51
import org.netbeans.modules.hudson.spi.BuilderConnector;
52
import org.netbeans.modules.hudson.ui.interfaces.OpenableInBrowser;
53
import org.openide.util.ChangeSupport;
54
import org.openide.util.WeakListeners;
55
56
public class HudsonFolderImpl implements HudsonFolder, OpenableInBrowser, HudsonChangeListener {
57
58
    private final ChangeSupport cs = new ChangeSupport(this);
59
    private final HudsonInstanceImpl instance;
60
    private final String name, url;
61
    private BuilderConnector.InstanceData children;
62
    private Collection<HudsonJob> jobs;
63
    private Collection<HudsonFolder> folders;
64
65
    HudsonFolderImpl(HudsonInstanceImpl instance, String name, String url) {
66
        this.instance = instance;
67
        this.name = name;
68
        this.url = url;
69
        instance.addHudsonChangeListener(WeakListeners.create(HudsonChangeListener.class, this, instance));
70
    }
71
72
    @Override public String getName() {
73
        return name;
74
    }
75
76
    @Override public String getUrl() {
77
        return url;
78
    }
79
80
    private synchronized void load() {
81
        if (children == null) {
82
            children = instance.getBuilderConnector().getInstanceData(this, true);
83
            jobs = instance.createJobs(children.getJobsData());
84
            folders = instance.createFolders(children.getFoldersData());
85
        }
86
    }
87
88
    @Override public Collection<HudsonJob> getJobs() {
89
        load();
90
        return jobs;
91
    }
92
93
    @Override public Collection<HudsonFolder> getFolders() {
94
        load();
95
        return folders;
96
    }
97
98
    @Override public HudsonInstance getInstance() {
99
        return instance;
100
    }
101
102
    @Override public String toString() {
103
        return url;
104
    }
105
106
    @Override public boolean equals(Object obj) {
107
        return obj instanceof HudsonFolderImpl && ((HudsonFolderImpl) obj).url.equals(url);
108
    }
109
110
    @Override public int hashCode() {
111
        return url.hashCode();
112
    }
113
114
    @Override public void addChangeListener(ChangeListener listener) {
115
        cs.addChangeListener(listener);
116
    }
117
    
118
    @Override public void removeChangeListener(ChangeListener listener) {
119
        cs.removeChangeListener(listener);
120
    }
121
122
    @Override public void stateChanged() {
123
        synchronized (this) {
124
            children = null;
125
        }
126
        cs.fireChange();
127
    }
128
129
    @Override public void contentChanged() {}
130
131
}
(-)a/hudson/src/org/netbeans/modules/hudson/impl/HudsonInstanceImpl.java (-1 / +19 lines)
Lines 64-69 Link Here
64
import org.netbeans.api.progress.ProgressHandleFactory;
64
import org.netbeans.api.progress.ProgressHandleFactory;
65
import org.netbeans.modules.hudson.api.HudsonChangeAdapter;
65
import org.netbeans.modules.hudson.api.HudsonChangeAdapter;
66
import org.netbeans.modules.hudson.api.HudsonChangeListener;
66
import org.netbeans.modules.hudson.api.HudsonChangeListener;
67
import org.netbeans.modules.hudson.api.HudsonFolder;
67
import org.netbeans.modules.hudson.api.HudsonInstance;
68
import org.netbeans.modules.hudson.api.HudsonInstance;
68
import org.netbeans.modules.hudson.api.HudsonJob;
69
import org.netbeans.modules.hudson.api.HudsonJob;
69
import org.netbeans.modules.hudson.api.HudsonJobBuild;
70
import org.netbeans.modules.hudson.api.HudsonJobBuild;
Lines 107-112 Link Here
107
    private final Task synchronization;
108
    private final Task synchronization;
108
    
109
    
109
    private Collection<HudsonJob> jobs = new ArrayList<HudsonJob>();
110
    private Collection<HudsonJob> jobs = new ArrayList<HudsonJob>();
111
    private Collection<HudsonFolder> folders = new ArrayList<HudsonFolder>();
110
    private Collection<HudsonView> views = new ArrayList<HudsonView>();
112
    private Collection<HudsonView> views = new ArrayList<HudsonView>();
111
    private HudsonView primaryView;
113
    private HudsonView primaryView;
112
    private final Collection<HudsonChangeListener> listeners = new ArrayList<HudsonChangeListener>();
114
    private final Collection<HudsonChangeListener> listeners = new ArrayList<HudsonChangeListener>();
Lines 220-225 Link Here
220
        forbidden = false;
222
        forbidden = false;
221
        version = null;
223
        version = null;
222
        jobs.clear();
224
        jobs.clear();
225
        folders.clear();
223
        views.clear();
226
        views.clear();
224
        primaryView = null;
227
        primaryView = null;
225
        
228
        
Lines 239-244 Link Here
239
        assert !(connector instanceof HudsonConnector);
242
        assert !(connector instanceof HudsonConnector);
240
        this.builderConnector = connector;
243
        this.builderConnector = connector;
241
        this.jobs.clear();
244
        this.jobs.clear();
245
        folders.clear();
242
        this.views.clear();
246
        this.views.clear();
243
        synchronize(false);
247
        synchronize(false);
244
    }
248
    }
Lines 273-278 Link Here
273
        return jobs;
277
        return jobs;
274
    }
278
    }
275
279
280
    @Override public synchronized Collection<HudsonFolder> getFolders() {
281
        return folders;
282
    }
283
276
    boolean isSalient(HudsonJobImpl job) {
284
    boolean isSalient(HudsonJobImpl job) {
277
        HudsonInstanceProperties props = getProperties();
285
        HudsonInstanceProperties props = getProperties();
278
        if (HudsonInstanceProperties.split(props.get(INSTANCE_SUPPRESSED_JOBS)).contains(job.getName())) {
286
        if (HudsonInstanceProperties.split(props.get(INSTANCE_SUPPRESSED_JOBS)).contains(job.getName())) {
Lines 377-382 Link Here
377
                        configureViews(instanceData.getViewsData());
385
                        configureViews(instanceData.getViewsData());
378
                        Collection<HudsonJob> retrieved = createJobs(
386
                        Collection<HudsonJob> retrieved = createJobs(
379
                                instanceData.getJobsData());
387
                                instanceData.getJobsData());
388
                        Collection<HudsonFolder> retrievedFolders = createFolders(instanceData.getFoldersData());
380
                        
389
                        
381
                        // Exit when instance is terminated
390
                        // Exit when instance is terminated
382
                        if (terminated) {
391
                        if (terminated) {
Lines 405-416 Link Here
405
                        }
414
                        }
406
415
407
                        // When there are no changes return and do not fire changes
416
                        // When there are no changes return and do not fire changes
408
                        if (getJobs().equals(retrieved) && oldViews.equals(getViews())) {
417
                        if (jobs.equals(retrieved) && folders.equals(retrievedFolders) && oldViews.equals(getViews())) {
409
                            return;
418
                            return;
410
                        }
419
                        }
411
                        
420
                        
412
                        // Update jobs
421
                        // Update jobs
413
                        jobs = retrieved;
422
                        jobs = retrieved;
423
                        folders = retrievedFolders;
414
424
415
                        // Fire all changes
425
                        // Fire all changes
416
                        fireContentChanges();
426
                        fireContentChanges();
Lines 551-556 Link Here
551
        return jobList;
561
        return jobList;
552
    }
562
    }
553
563
564
    public Collection<HudsonFolder> createFolders(Collection<BuilderConnector.FolderData> foldersData) {
565
        Collection<HudsonFolder> result = new ArrayList<HudsonFolder>();
566
        for (BuilderConnector.FolderData datum : foldersData) {
567
            result.add(new HudsonFolderImpl(this, datum.getName(), datum.getUrl()));
568
        }
569
        return result;
570
    }
571
554
    private void configureViews(Collection<BuilderConnector.ViewData> viewsData) {
572
    private void configureViews(Collection<BuilderConnector.ViewData> viewsData) {
555
573
556
        Collection<HudsonView> viewList = new ArrayList<HudsonView>();
574
        Collection<HudsonView> viewList = new ArrayList<HudsonView>();
(-)a/hudson/src/org/netbeans/modules/hudson/spi/BuilderConnector.java (+49 lines)
Lines 42-53 Link Here
42
package org.netbeans.modules.hudson.spi;
42
package org.netbeans.modules.hudson.spi;
43
43
44
import java.util.Collection;
44
import java.util.Collection;
45
import java.util.Collections;
45
import java.util.LinkedList;
46
import java.util.LinkedList;
46
import java.util.List;
47
import java.util.List;
47
import java.util.concurrent.atomic.AtomicBoolean;
48
import java.util.concurrent.atomic.AtomicBoolean;
48
import java.util.concurrent.atomic.AtomicReference;
49
import java.util.concurrent.atomic.AtomicReference;
49
import org.netbeans.api.annotations.common.CheckForNull;
50
import org.netbeans.api.annotations.common.CheckForNull;
50
import org.netbeans.api.annotations.common.NonNull;
51
import org.netbeans.api.annotations.common.NonNull;
52
import org.netbeans.modules.hudson.api.HudsonFolder;
51
import org.netbeans.modules.hudson.api.HudsonJob;
53
import org.netbeans.modules.hudson.api.HudsonJob;
52
import org.netbeans.modules.hudson.api.HudsonJob.Color;
54
import org.netbeans.modules.hudson.api.HudsonJob.Color;
53
import org.netbeans.modules.hudson.api.HudsonJobBuild;
55
import org.netbeans.modules.hudson.api.HudsonJobBuild;
Lines 76-81 Link Here
76
            boolean authentication);
78
            boolean authentication);
77
79
78
    /**
80
    /**
81
     * Like {@link #getInstanceData(boolean)} but gets the contents of a folder rather than top level.
82
     * Consider abstract; the default implementation produces an empty result.
83
     * @since XXX
84
     */
85
    public /*abstract*/ @NonNull InstanceData getInstanceData(@NonNull HudsonFolder parentFolder, boolean authentication) {
86
        return new InstanceData(Collections.<JobData>emptyList(), Collections.<ViewData>emptyList(), Collections.<FolderData>emptyList());
87
    }
88
89
    /**
79
     * Get builds for the specified job.
90
     * Get builds for the specified job.
80
     */
91
     */
81
    public abstract @NonNull Collection<BuildData> getJobBuildsData(
92
    public abstract @NonNull Collection<BuildData> getJobBuildsData(
Lines 336-341 Link Here
336
        }
347
        }
337
    }
348
    }
338
349
350
    /** @since XXX */
351
    public static final class FolderData {
352
353
        private String name;
354
        private String url;
355
356
        public String getName() {
357
            return name;
358
        }
359
360
        public void setName(String name) {
361
            this.name = name;
362
        }
363
364
        public String getUrl() {
365
            return url;
366
        }
367
368
        public void setUrl(String url) {
369
            this.url = url;
370
        }
371
372
    }
373
339
    /**
374
    /**
340
     * Type for storing build module data
375
     * Type for storing build module data
341
     */
376
     */
Lines 428-437 Link Here
428
463
429
        private Collection<JobData> jobsData;
464
        private Collection<JobData> jobsData;
430
        private Collection<ViewData> viewsData;
465
        private Collection<ViewData> viewsData;
466
        private final Collection<FolderData> foldersData;
431
467
468
        @Deprecated
432
        public InstanceData(Collection<JobData> jobsData, Collection<ViewData> viewsData) {
469
        public InstanceData(Collection<JobData> jobsData, Collection<ViewData> viewsData) {
470
            this(jobsData, viewsData, Collections.<FolderData>emptySet());
471
        }
472
473
        /** @since XXX */
474
        public InstanceData(Collection<JobData> jobsData, Collection<ViewData> viewsData, Collection<FolderData> foldersData) {
433
            this.jobsData = jobsData;
475
            this.jobsData = jobsData;
434
            this.viewsData = viewsData;
476
            this.viewsData = viewsData;
477
            this.foldersData = foldersData;
435
        }
478
        }
436
479
437
        public Collection<JobData> getJobsData() {
480
        public Collection<JobData> getJobsData() {
Lines 441-445 Link Here
441
        public Collection<ViewData> getViewsData() {
484
        public Collection<ViewData> getViewsData() {
442
            return viewsData;
485
            return viewsData;
443
        }
486
        }
487
488
        /** @since XXX */
489
        public Collection<FolderData> getFoldersData() {
490
            return foldersData;
491
        }
492
444
    }
493
    }
445
}
494
}
(-)a/hudson/src/org/netbeans/modules/hudson/ui/nodes/HudsonFolderNode.java (+125 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2013 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.hudson.ui.nodes;
44
45
import java.awt.Image;
46
import java.util.ArrayList;
47
import java.util.List;
48
import javax.swing.Action;
49
import javax.swing.event.ChangeEvent;
50
import javax.swing.event.ChangeListener;
51
import org.netbeans.modules.hudson.api.HudsonFolder;
52
import org.netbeans.modules.hudson.api.HudsonJob;
53
import org.netbeans.modules.hudson.ui.actions.OpenUrlAction;
54
import org.netbeans.modules.hudson.ui.interfaces.OpenableInBrowser;
55
import org.openide.filesystems.FileUtil;
56
import org.openide.loaders.DataFolder;
57
import org.openide.nodes.AbstractNode;
58
import org.openide.nodes.ChildFactory;
59
import org.openide.nodes.Children;
60
import org.openide.nodes.Node;
61
import org.openide.util.Union2;
62
import org.openide.util.WeakListeners;
63
import org.openide.util.lookup.Lookups;
64
65
class HudsonFolderNode extends AbstractNode {
66
67
    private static final Node iconDelegate = DataFolder.findFolder(FileUtil.getConfigRoot()).getNodeDelegate();
68
69
    private final HudsonFolder folder;
70
71
    HudsonFolderNode(HudsonFolder folder) {
72
        super(Children.create(new HudsonFolderChildren(folder), true), Lookups.singleton(folder));
73
        this.folder = folder;
74
        setName(folder.getName());
75
    }
76
77
    public @Override Image getIcon(int type) {
78
        return iconDelegate.getIcon(type);
79
    }
80
81
    public @Override Image getOpenedIcon(int type) {
82
        return iconDelegate.getOpenedIcon(type);
83
    }
84
85
    @Override public Action[] getActions(boolean context) {
86
        List<Action> actions = new ArrayList<Action>();
87
        if (folder instanceof OpenableInBrowser) {
88
            actions.add(OpenUrlAction.forOpenable((OpenableInBrowser) folder));
89
        }
90
        return actions.toArray(new Action[actions.size()]);
91
    }
92
93
    private static final class HudsonFolderChildren extends ChildFactory.Detachable<Union2<HudsonJob,HudsonFolder>> implements ChangeListener {
94
95
        private final HudsonFolder folder;
96
97
        HudsonFolderChildren(HudsonFolder folder) {
98
            this.folder = folder;
99
        }
100
101
        @Override protected boolean createKeys(List<Union2<HudsonJob,HudsonFolder>> toPopulate) {
102
            for (HudsonFolder subfolder : folder.getFolders()) {
103
                toPopulate.add(Union2.<HudsonJob,HudsonFolder>createSecond(subfolder));
104
            }
105
            for (HudsonJob job : folder.getJobs()) {
106
                toPopulate.add(Union2.<HudsonJob,HudsonFolder>createFirst(job));
107
            }
108
            return true;
109
        }
110
111
        @Override protected Node createNodeForKey(Union2<HudsonJob,HudsonFolder> key) {
112
            return key.hasFirst() ? new HudsonJobNode(key.first()) : new HudsonFolderNode(key.second());
113
        }
114
115
        @Override protected void addNotify() {
116
            folder.addChangeListener(WeakListeners.change(this, folder));
117
        }
118
119
        @Override public void stateChanged(ChangeEvent e) {
120
            refresh(false);
121
        }
122
123
    }
124
125
}
(-)a/hudson/src/org/netbeans/modules/hudson/ui/nodes/HudsonInstanceNode.java (-6 / +17 lines)
Lines 47-57 Link Here
47
import java.io.IOException;
47
import java.io.IOException;
48
import java.util.ArrayList;
48
import java.util.ArrayList;
49
import java.util.Collections;
49
import java.util.Collections;
50
import java.util.LinkedList;
50
import java.util.List;
51
import java.util.List;
51
import java.util.prefs.PreferenceChangeEvent;
52
import java.util.prefs.PreferenceChangeEvent;
52
import java.util.prefs.PreferenceChangeListener;
53
import java.util.prefs.PreferenceChangeListener;
53
import javax.swing.Action;
54
import javax.swing.Action;
54
import org.netbeans.modules.hudson.api.HudsonChangeListener;
55
import org.netbeans.modules.hudson.api.HudsonChangeListener;
56
import org.netbeans.modules.hudson.api.HudsonFolder;
55
import org.netbeans.modules.hudson.api.HudsonInstance;
57
import org.netbeans.modules.hudson.api.HudsonInstance;
56
import org.netbeans.modules.hudson.api.HudsonJob;
58
import org.netbeans.modules.hudson.api.HudsonJob;
57
import org.netbeans.modules.hudson.api.HudsonJob.Color;
59
import org.netbeans.modules.hudson.api.HudsonJob.Color;
Lines 65-70 Link Here
65
import org.openide.nodes.Children;
67
import org.openide.nodes.Children;
66
import org.openide.nodes.Node;
68
import org.openide.nodes.Node;
67
import org.openide.util.NbBundle.Messages;
69
import org.openide.util.NbBundle.Messages;
70
import org.openide.util.Union2;
68
import org.openide.util.lookup.Lookups;
71
import org.openide.util.lookup.Lookups;
69
72
70
/**
73
/**
Lines 195-201 Link Here
195
     */
198
     */
196
    public static final String SELECTED_VIEW = "view"; // NOI18N
199
    public static final String SELECTED_VIEW = "view"; // NOI18N
197
    
200
    
198
    private static class InstanceNodeChildren extends Children.Keys<HudsonJob> implements HudsonChangeListener {
201
    private static class InstanceNodeChildren extends Children.Keys<Union2<HudsonJob,HudsonFolder>> implements HudsonChangeListener {
199
        
202
        
200
        private final HudsonInstanceImpl instance;
203
        private final HudsonInstanceImpl instance;
201
        
204
        
Lines 209-223 Link Here
209
            });
212
            });
210
        }
213
        }
211
        
214
        
212
        @Override protected Node[] createNodes(HudsonJob job) {
215
        @Override protected Node[] createNodes(Union2<HudsonJob,HudsonFolder> item) {
213
            return new Node[] {new HudsonJobNode(job)};
216
            return new Node[] {item.hasFirst() ? new HudsonJobNode(item.first()) : new HudsonFolderNode(item.second())};
214
        }
217
        }
215
        
218
        
216
        @Override
219
        @Override
217
        protected void addNotify() {
220
        protected void addNotify() {
218
            super.addNotify();
221
            super.addNotify();
219
            if (!instance.isConnected()/* && seems undesirable: !instance.isForbidden()*/) {
222
            if (!instance.isConnected()/* && seems undesirable: !instance.isForbidden()*/) {
220
                setKeys(Collections.<HudsonJob>emptySet());
223
                setKeys(Collections.<Union2<HudsonJob,HudsonFolder>>emptySet());
221
                instance.synchronize(true);
224
                instance.synchronize(true);
222
            } else {
225
            } else {
223
                refreshKeys();
226
                refreshKeys();
Lines 226-232 Link Here
226
        
229
        
227
        @Override
230
        @Override
228
        protected void removeNotify() {
231
        protected void removeNotify() {
229
            setKeys(Collections.<HudsonJob>emptySet());
232
            setKeys(Collections.<Union2<HudsonJob,HudsonFolder>>emptySet());
230
            super.removeNotify();
233
            super.removeNotify();
231
        }
234
        }
232
        
235
        
Lines 249-255 Link Here
249
                jobs.add(job);
252
                jobs.add(job);
250
            }
253
            }
251
            Collections.sort(jobs);
254
            Collections.sort(jobs);
252
            setKeys(jobs);
255
            List<Union2<HudsonJob,HudsonFolder>> items = new LinkedList<Union2<HudsonJob,HudsonFolder>>();
256
            for (HudsonFolder folder : instance.getFolders()) {
257
                // XXX ideally should restrict by selected view, like jobs
258
                items.add(Union2.<HudsonJob,HudsonFolder>createSecond(folder));
259
            }
260
            for (HudsonJob job : jobs) {
261
                items.add(Union2.<HudsonJob,HudsonFolder>createFirst(job));
262
            }
263
            setKeys(items);
253
        }
264
        }
254
        
265
        
255
        @Override public void stateChanged() {
266
        @Override public void stateChanged() {

Return to bug 215135