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/manifest.mf (-1 / +1 lines)
Lines 2-6 Link Here
2
OpenIDE-Module: org.netbeans.modules.hudson
2
OpenIDE-Module: org.netbeans.modules.hudson
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/hudson/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/hudson/Bundle.properties
4
OpenIDE-Module-Layer: org/netbeans/modules/hudson/layer.xml
4
OpenIDE-Module-Layer: org/netbeans/modules/hudson/layer.xml
5
OpenIDE-Module-Specification-Version: 1.31
5
OpenIDE-Module-Specification-Version: 1.32
6
6
(-)a/hudson/src/org/netbeans/modules/hudson/spi/ProjectHudsonProvider.java (-18 / +116 lines)
Lines 45-50 Link Here
45
package org.netbeans.modules.hudson.spi;
45
package org.netbeans.modules.hudson.spi;
46
46
47
import java.net.URI;
47
import java.net.URI;
48
import java.util.Arrays;
49
import java.util.Collection;
48
import java.util.HashMap;
50
import java.util.HashMap;
49
import java.util.Map;
51
import java.util.Map;
50
import java.util.logging.Level;
52
import java.util.logging.Level;
Lines 54-59 Link Here
54
import org.netbeans.api.annotations.common.CheckForNull;
56
import org.netbeans.api.annotations.common.CheckForNull;
55
import org.netbeans.api.project.Project;
57
import org.netbeans.api.project.Project;
56
import org.netbeans.api.project.ui.OpenProjects;
58
import org.netbeans.api.project.ui.OpenProjects;
59
import org.netbeans.modules.hudson.api.HudsonFolder;
57
import org.netbeans.modules.hudson.api.HudsonInstance;
60
import org.netbeans.modules.hudson.api.HudsonInstance;
58
import org.netbeans.modules.hudson.api.HudsonJob;
61
import org.netbeans.modules.hudson.api.HudsonJob;
59
import org.netbeans.modules.hudson.impl.HudsonManagerImpl;
62
import org.netbeans.modules.hudson.impl.HudsonManagerImpl;
Lines 144-151 Link Here
144
     */
147
     */
145
    public static final class Association {
148
    public static final class Association {
146
149
147
        private final String serverURL;
150
        private final String jobURL;
148
        private final String jobName;
151
        /** Server URL (first), sequence of folders, job name (last). */
152
        private final String[] jobPath;
149
153
150
        /**
154
        /**
151
         * Creates an association.
155
         * Creates an association.
Lines 164-171 Link Here
164
            if (jobName != null && jobName.indexOf('/') != -1) {
168
            if (jobName != null && jobName.indexOf('/') != -1) {
165
                throw new IllegalArgumentException("No slashes permitted in job name: " + jobName);
169
                throw new IllegalArgumentException("No slashes permitted in job name: " + jobName);
166
            }
170
            }
167
            this.serverURL = serverURL;
171
            this.jobURL = getStandardJobUrl(serverURL, jobName);
168
            this.jobName = jobName;
172
            this.jobPath = new String[]{serverURL, jobName};
173
        }
174
175
        private static String getStandardJobUrl(String serverURL, String jobName) {
176
            return jobName != null
177
                    ? serverURL + "job/" + Utilities.uriEncode(jobName) + "/" // NOI18N
178
                    : serverURL;
179
        }
180
181
        /**
182
         * Creates an association.
183
         *
184
         * @param job URL
185
         * @throws IllegalArgumentException if parameter has invalid syntax
186
         * @since hudson/1.32
187
         */
188
        public Association(String jobURL) throws IllegalArgumentException {
189
            URI.create(jobURL); // check syntax
190
            if (!jobURL.endsWith("/")) { // NOI18N
191
                throw new IllegalArgumentException(jobURL + " must end in a slash"); // NOI18N
192
            }
193
            this.jobURL = jobURL;
194
            this.jobPath = extractJobPath(jobURL);
195
        }
196
197
        private static String[] extractJobPath(String jobURL) throws IllegalArgumentException {
198
            Matcher m = Pattern.compile("(https?://.+?/)((?:job/(?:[^/]+)/)*)").matcher(jobURL); // NOI18N
199
            if (!m.matches()) {
200
                throw new IllegalArgumentException("Cannot extract job path: " + jobURL); //NOI18N
201
            } else {
202
                String rawPath = m.group(2);
203
                if (rawPath == null || rawPath.isEmpty()) {
204
                    return new String[]{m.group(1)};
205
                } else {
206
                    String[] elements = rawPath.split("/");
207
                    assert elements.length > 0 && (elements.length % 2) == 0;
208
                    String[] result = new String[(elements.length / 2) + 1];
209
                    result[0] = m.group(1); // server URL
210
                    for (int i = 0; i < elements.length; i++) {
211
                        String element = elements[i];
212
                        if (i % 2 == 0) {
213
                            assert "job".equals(element);
214
                        } else {
215
                            String decoded = Utilities.uriDecode(element);
216
                            if (decoded.trim().isEmpty()) {
217
                                throw new IllegalArgumentException("Empty job name: " + jobURL); //NOI18N
218
                            }
219
                            result[(i / 2) + 1] = decoded;
220
                        }
221
                    }
222
                    return result;
223
                }
224
            }
169
        }
225
        }
170
226
171
        /**
227
        /**
Lines 174-194 Link Here
174
         * @return an association with the same server URL and job name
230
         * @return an association with the same server URL and job name
175
         */
231
         */
176
        public static Association forJob(HudsonJob job) {
232
        public static Association forJob(HudsonJob job) {
177
            return new Association(job.getInstance().getUrl(), job.getName());
233
            return new Association(job.getUrl());
178
        }
234
        }
179
235
180
        /**
236
        /**
181
         * @return the root URL of the server ending in slash, e.g. {@code http://deadlock.netbeans.org/hudson/}
237
         * @return the root URL of the server ending in slash, e.g. {@code http://deadlock.netbeans.org/hudson/}
182
         */
238
         */
183
        public String getServerUrl() {
239
        public String getServerUrl() {
184
            return serverURL;
240
            return jobPath[0];
185
        }
241
        }
186
242
187
        /**
243
        /**
188
         * @return the code name of the job on that server; may be null
244
         * @return the code name of the job on that server; may be null
189
         */
245
         */
190
        public String getJobName() {
246
        public String getJobName() {
191
            return jobName;
247
            return jobPath.length > 1 ? jobPath[jobPath.length - 1] : null;
248
        }
249
250
        /**
251
         * Get copy of job path. Not private - called from tests.
252
         */
253
        String[] getJobPath() {
254
            return Arrays.copyOf(jobPath, jobPath.length);
192
        }
255
        }
193
256
194
        /**
257
        /**
Lines 196-210 Link Here
196
         * @return a job with the name {@link #getJobName} on the server with the same {@link #getServerUrl}, or null
259
         * @return a job with the name {@link #getJobName} on the server with the same {@link #getServerUrl}, or null
197
         */
260
         */
198
        public @CheckForNull HudsonJob getJob() {
261
        public @CheckForNull HudsonJob getJob() {
199
            if (jobName == null) {
262
            if (jobPath == null || jobPath.length < 2) { // no job name
200
                return null;
263
                return null;
201
            }
264
            }
202
            HudsonInstance instance = HudsonManagerImpl.getDefault().getInstance(serverURL);
265
            HudsonInstance instance = HudsonManagerImpl.getDefault().getInstance(jobPath[0]);
203
            if (instance == null) {
266
            if (instance == null) {
204
                return null;
267
                return null;
205
            }
268
            }
206
            for (HudsonJob job : instance.getJobs()) {
269
            if (jobPath.length == 2) {
207
                if (job.getName().equals(jobName)) {
270
                return findJobByName(instance.getJobs(), jobPath[1]);
271
            } else {
272
                HudsonFolder lastFolder = null;
273
                for (int i = 1; i < jobPath.length; i++) {
274
                    String name = jobPath[i];
275
                    if (i == 1) {
276
                        lastFolder = findFolderByName(instance.getFolders(), name);
277
                    } else if (i < jobPath.length - 1 && lastFolder != null) {
278
                        lastFolder = findFolderByName(lastFolder.getFolders(), name);
279
                    } else if (lastFolder != null) {
280
                        return findJobByName(lastFolder.getJobs(), name);
281
                    }
282
                }
283
            }
284
            return null;
285
        }
286
287
        /**
288
         * Find a folder of specified name in a collection of folders.
289
         *
290
         * @return The folder with name {@code name}, or null if not found.
291
         */
292
        private HudsonFolder findFolderByName(Collection<HudsonFolder> folders,
293
                String name) {
294
            for (HudsonFolder folder : folders) {
295
                if (name.equals(folder.getName())) {
296
                    return folder;
297
                }
298
            }
299
            return null;
300
        }
301
302
        /**
303
         * Find a job of specified name in a collection of jobs.
304
         *
305
         * @return The job with name {@code name}, or null if not found.
306
         */
307
        private HudsonJob findJobByName(Collection<HudsonJob> jobs,
308
                String name) {
309
            for (HudsonJob job : jobs) {
310
                if (name.equals(job.getName())) {
208
                    return job;
311
                    return job;
209
                }
312
                }
210
            }
313
            }
Lines 226-232 Link Here
226
         * URL of either job or server root.
329
         * URL of either job or server root.
227
         */
330
         */
228
        public @Override String toString() {
331
        public @Override String toString() {
229
            return jobName != null ? serverURL + "job/" + Utilities.uriEncode(jobName) + "/" : serverURL; // NOI18N
332
            return jobURL;
230
        }
333
        }
231
334
232
        /**
335
        /**
Lines 234-246 Link Here
234
         * @return an association based on parsing a Hudson job or root URL, or null
337
         * @return an association based on parsing a Hudson job or root URL, or null
235
         */
338
         */
236
        public static Association fromString(String s) {
339
        public static Association fromString(String s) {
237
            Matcher m = Pattern.compile("(https?://.+?/)(?:job/([^/]+)/?)?").matcher(s); // NOI18N
238
            if (!m.matches()) {
239
                return null;
240
            }
241
            String jobNameRaw = m.group(2);
242
            try {
340
            try {
243
                return new Association(m.group(1), jobNameRaw != null ? Utilities.uriDecode(jobNameRaw) : null);
341
                return new Association(s);
244
            } catch (IllegalArgumentException x) {
342
            } catch (IllegalArgumentException x) {
245
                Logger.getLogger(ProjectHudsonProvider.class.getName()).log(Level.WARNING, "Bad URL: {0}", s);
343
                Logger.getLogger(ProjectHudsonProvider.class.getName()).log(Level.WARNING, "Bad URL: {0}", s);
246
                return null;
344
                return null;
(-)a/hudson/test/unit/src/org/netbeans/modules/hudson/spi/ProjectHudsonProviderTest.java (+13 lines)
Lines 76-79 Link Here
76
        assertEquals("Some Job", Association.fromString("http://nowhere.net/hudson/view/someview/job/Some%20Job/").getJobName());
76
        assertEquals("Some Job", Association.fromString("http://nowhere.net/hudson/view/someview/job/Some%20Job/").getJobName());
77
    }
77
    }
78
78
79
    public void testAssociationOfHudsonJobsInFolderHierarchy() {
80
        Association a = Association.fromString(
81
                "http://localhost:8080/app/hudson/job/folder%201/job/folder%201a/job/TestJob/");
82
        assertEquals("http://localhost:8080/app/hudson/", a.getServerUrl());
83
        assertEquals("TestJob", a.getJobName());
84
        String[] expectedPath = {"http://localhost:8080/app/hudson/",
85
            "folder 1", "folder 1a", "TestJob"};
86
        assertEquals("Job path length is wrong",
87
                expectedPath.length, a.getJobPath().length);
88
        for (int i = 0; i < expectedPath.length; i++) {
89
            assertEquals(expectedPath[i], a.getJobPath()[i]);
90
        }
91
    }
79
}
92
}

Return to bug 215135