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 145-151
Link Here
|
145 |
public static final class Association { |
148 |
public static final class Association { |
146 |
|
149 |
|
147 |
private final String serverURL; |
150 |
private final String serverURL; |
|
|
151 |
private final String jobURL; |
148 |
private final String jobName; |
152 |
private final String jobName; |
|
|
153 |
private final String[] jobPath; |
149 |
|
154 |
|
150 |
/** |
155 |
/** |
151 |
* Creates an association. |
156 |
* Creates an association. |
Lines 165-171
Link Here
|
165 |
throw new IllegalArgumentException("No slashes permitted in job name: " + jobName); |
170 |
throw new IllegalArgumentException("No slashes permitted in job name: " + jobName); |
166 |
} |
171 |
} |
167 |
this.serverURL = serverURL; |
172 |
this.serverURL = serverURL; |
|
|
173 |
this.jobURL = getStandardJobUrl(serverURL, jobName); |
168 |
this.jobName = jobName; |
174 |
this.jobName = jobName; |
|
|
175 |
this.jobPath = new String[]{jobName}; |
176 |
} |
177 |
|
178 |
private static String getStandardJobUrl(String serverURL, String jobName) { |
179 |
return jobName != null |
180 |
? serverURL + "job/" + Utilities.uriEncode(jobName) + "/" // NOI18N |
181 |
: serverURL; |
182 |
} |
183 |
|
184 |
/** |
185 |
* Creates an association. |
186 |
* |
187 |
* @param job URL |
188 |
* @throws IllegalArgumentException if parameter has invalid syntax |
189 |
* @since hudson/1.32 |
190 |
*/ |
191 |
public Association(String jobURL) throws IllegalArgumentException { |
192 |
URI.create(jobURL); // check syntax |
193 |
if (!jobURL.endsWith("/")) { // NOI18N |
194 |
throw new IllegalArgumentException(jobURL + " must end in a slash"); // NOI18N |
195 |
} |
196 |
this.jobURL = jobURL; |
197 |
this.serverURL = extractServerURL(jobURL); |
198 |
this.jobPath = extractJobPath(jobURL); |
199 |
this.jobName = jobPath != null |
200 |
? jobPath[jobPath.length - 1] |
201 |
: null; |
202 |
} |
203 |
|
204 |
private static String extractServerURL(String jobURL) throws IllegalArgumentException { |
205 |
Matcher m = Pattern.compile("(https?://.+?/)(job/([^/]+)/)*").matcher(jobURL); // NOI18N |
206 |
if (!m.matches()) { |
207 |
throw new IllegalArgumentException("Cannot extract server URL: " + jobURL); //NOI18N |
208 |
} else { |
209 |
m.group(1); |
210 |
return m.group(1); |
211 |
} |
212 |
} |
213 |
|
214 |
private static String[] extractJobPath(String jobURL) throws IllegalArgumentException { |
215 |
Matcher m = Pattern.compile("(?:https?://.+?/)(?:[^/]+/)*?((?:job/(?:[^/]+)/)*)").matcher(jobURL); // NOI18N |
216 |
if (!m.matches()) { |
217 |
throw new IllegalArgumentException("Cannot extract job path: " + jobURL); //NOI18N |
218 |
} else { |
219 |
String rawPath = m.group(1); |
220 |
if (rawPath == null || rawPath.isEmpty()) { |
221 |
return null; |
222 |
} else { |
223 |
String[] elements = rawPath.split("/"); |
224 |
assert elements.length > 0 && (elements.length % 2) == 0; |
225 |
String[] result = new String[elements.length / 2]; |
226 |
for (int i = 0; i < elements.length; i++) { |
227 |
String element = elements[i]; |
228 |
if (i % 2 == 0) { |
229 |
assert "job".equals(element); |
230 |
} else { |
231 |
String decoded = Utilities.uriDecode(element); |
232 |
if (decoded.trim().isEmpty()) { |
233 |
throw new IllegalArgumentException("Empty job name: " + jobURL); //NOI18N |
234 |
} |
235 |
result[i / 2] = decoded; |
236 |
} |
237 |
} |
238 |
return result; |
239 |
} |
240 |
} |
169 |
} |
241 |
} |
170 |
|
242 |
|
171 |
/** |
243 |
/** |
Lines 174-180
Link Here
|
174 |
* @return an association with the same server URL and job name |
246 |
* @return an association with the same server URL and job name |
175 |
*/ |
247 |
*/ |
176 |
public static Association forJob(HudsonJob job) { |
248 |
public static Association forJob(HudsonJob job) { |
177 |
return new Association(job.getInstance().getUrl(), job.getName()); |
249 |
return new Association(job.getUrl()); |
178 |
} |
250 |
} |
179 |
|
251 |
|
180 |
/** |
252 |
/** |
Lines 192-210
Link Here
|
192 |
} |
264 |
} |
193 |
|
265 |
|
194 |
/** |
266 |
/** |
|
|
267 |
* Get copy of job path. Not private - called from tests. |
268 |
*/ |
269 |
String[] getJobPath() { |
270 |
return Arrays.copyOf(jobPath, jobPath.length); |
271 |
} |
272 |
|
273 |
/** |
195 |
* Finds the corresponding job on a registered server, if any. |
274 |
* Finds the corresponding job on a registered server, if any. |
196 |
* @return a job with the name {@link #getJobName} on the server with the same {@link #getServerUrl}, or null |
275 |
* @return a job with the name {@link #getJobName} on the server with the same {@link #getServerUrl}, or null |
197 |
*/ |
276 |
*/ |
198 |
public @CheckForNull HudsonJob getJob() { |
277 |
public @CheckForNull HudsonJob getJob() { |
199 |
if (jobName == null) { |
278 |
if (jobPath == null) { |
200 |
return null; |
279 |
return null; |
201 |
} |
280 |
} |
202 |
HudsonInstance instance = HudsonManagerImpl.getDefault().getInstance(serverURL); |
281 |
HudsonInstance instance = HudsonManagerImpl.getDefault().getInstance(serverURL); |
203 |
if (instance == null) { |
282 |
if (instance == null) { |
204 |
return null; |
283 |
return null; |
205 |
} |
284 |
} |
206 |
for (HudsonJob job : instance.getJobs()) { |
285 |
if (jobPath.length == 1) { |
207 |
if (job.getName().equals(jobName)) { |
286 |
for (HudsonJob job : instance.getJobs()) { |
|
|
287 |
if (job.getName().equals(jobName)) { |
288 |
return job; |
289 |
} |
290 |
} |
291 |
return null; |
292 |
} else { |
293 |
HudsonFolder lastFolder = null; |
294 |
for (int i = 0; i < jobPath.length; i++) { |
295 |
String name = jobPath[i]; |
296 |
if (i == 0) { |
297 |
lastFolder = findFolderByName(instance.getFolders(), name); |
298 |
} else if (i < jobPath.length - 1 && lastFolder != null) { |
299 |
lastFolder = findFolderByName(lastFolder.getFolders(), name); |
300 |
} else if (lastFolder != null) { |
301 |
return findJobByName(lastFolder.getJobs(), name); |
302 |
} |
303 |
} |
304 |
} |
305 |
return null; |
306 |
} |
307 |
|
308 |
/** |
309 |
* Find a folder of specified name in a collection of folders. |
310 |
* |
311 |
* @return The folder with name {@code name}, or null if not found. |
312 |
*/ |
313 |
private HudsonFolder findFolderByName(Collection<HudsonFolder> folders, |
314 |
String name) { |
315 |
for (HudsonFolder folder : folders) { |
316 |
if (name.equals(folder.getName())) { |
317 |
return folder; |
318 |
} |
319 |
} |
320 |
return null; |
321 |
} |
322 |
|
323 |
/** |
324 |
* Find a job of specified name in a collection of jobs. |
325 |
* |
326 |
* @return The job with name {@code name}, or null if not found. |
327 |
*/ |
328 |
private HudsonJob findJobByName(Collection<HudsonJob> jobs, |
329 |
String name) { |
330 |
for (HudsonJob job : jobs) { |
331 |
if (name.equals(job.getName())) { |
208 |
return job; |
332 |
return job; |
209 |
} |
333 |
} |
210 |
} |
334 |
} |
Lines 226-232
Link Here
|
226 |
* URL of either job or server root. |
350 |
* URL of either job or server root. |
227 |
*/ |
351 |
*/ |
228 |
public @Override String toString() { |
352 |
public @Override String toString() { |
229 |
return jobName != null ? serverURL + "job/" + Utilities.uriEncode(jobName) + "/" : serverURL; // NOI18N |
353 |
return jobURL; |
230 |
} |
354 |
} |
231 |
|
355 |
|
232 |
/** |
356 |
/** |
Lines 234-246
Link Here
|
234 |
* @return an association based on parsing a Hudson job or root URL, or null |
358 |
* @return an association based on parsing a Hudson job or root URL, or null |
235 |
*/ |
359 |
*/ |
236 |
public static Association fromString(String s) { |
360 |
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 { |
361 |
try { |
243 |
return new Association(m.group(1), jobNameRaw != null ? Utilities.uriDecode(jobNameRaw) : null); |
362 |
return new Association(s); |
244 |
} catch (IllegalArgumentException x) { |
363 |
} catch (IllegalArgumentException x) { |
245 |
Logger.getLogger(ProjectHudsonProvider.class.getName()).log(Level.WARNING, "Bad URL: {0}", s); |
364 |
Logger.getLogger(ProjectHudsonProvider.class.getName()).log(Level.WARNING, "Bad URL: {0}", s); |
246 |
return null; |
365 |
return null; |