26
26
27
27
import static jenkins .model .lazy .AbstractLazyLoadRunMap .Direction .ASC ;
28
28
import static jenkins .model .lazy .AbstractLazyLoadRunMap .Direction .DESC ;
29
+ import static jenkins .model .lazy .AbstractLazyLoadRunMap .Direction .EXACT ;
29
30
30
31
import edu .umd .cs .findbugs .annotations .CheckForNull ;
31
32
import hudson .model .Job ;
39
40
import java .util .Collection ;
40
41
import java .util .Collections ;
41
42
import java .util .Comparator ;
42
- import java .util .Iterator ;
43
43
import java .util .Map ;
44
+ import java .util .NavigableMap ;
44
45
import java .util .NoSuchElementException ;
45
46
import java .util .Set ;
46
47
import java .util .SortedMap ;
96
97
public abstract class AbstractLazyLoadRunMap <R > extends AbstractMap <Integer , R > implements SortedMap <Integer , R > {
97
98
private final CopyOnWriteMap .Tree <Integer , BuildReference <R >> core = new CopyOnWriteMap .Tree <>(
98
99
Collections .reverseOrder ());
99
- private final BuildReferenceMapAdapter <R > adapter = new BuildReferenceMapAdapter <>( core ,
100
- this :: resolveBuildRef , this :: getNumberOf , this :: getBuildClass ) {
100
+ private final BuildReferenceMapAdapter . Resolver <R > buildResolver = new BuildReferenceMapAdapterResolver ();
101
+ private final BuildReferenceMapAdapter < R > adapter = new BuildReferenceMapAdapter <>( core , buildResolver ) {
101
102
@ Override
102
103
protected boolean removeValue (R value ) {
103
104
return AbstractLazyLoadRunMap .this .removeValue (value );
@@ -260,7 +261,7 @@ public SortedMap<Integer, R> getLoadedBuilds() {
260
261
res .put (entry .getKey (), buildRef );
261
262
}
262
263
}
263
- return new BuildReferenceMapAdapter <>(res , this :: resolveBuildRef , this :: getNumberOf , this :: getBuildClass );
264
+ return new BuildReferenceMapAdapter <>(res , buildResolver );
264
265
}
265
266
266
267
/**
@@ -286,16 +287,12 @@ public SortedMap<Integer, R> tailMap(Integer fromKey) {
286
287
287
288
@ Override
288
289
public Integer firstKey () {
289
- R r = newestBuild ();
290
- if (r == null ) throw new NoSuchElementException ();
291
- return getNumberOf (r );
290
+ return adapter .firstKey ();
292
291
}
293
292
294
293
@ Override
295
294
public Integer lastKey () {
296
- R r = oldestBuild ();
297
- if (r == null ) throw new NoSuchElementException ();
298
- return getNumberOf (r );
295
+ return adapter .lastKey ();
299
296
}
300
297
301
298
public R newestBuild () {
@@ -339,48 +336,27 @@ public boolean runExists(int number) {
339
336
* If DESC, finds the closest #M that satisfies M ≤ N.
340
337
*/
341
338
public @ CheckForNull R search (final int n , final Direction d ) {
342
- switch (d ) {
343
- case EXACT :
344
- return getByNumber (n );
345
- case ASC :
346
- for (int m : core .descendingMap ().keySet ()) {
347
- if (m < n ) {
348
- continue ;
349
- }
350
- R r = getByNumber (m );
351
- if (r != null ) {
352
- return r ;
353
- }
354
- }
355
- return null ;
356
- case DESC :
357
- Iterator <Integer > iterator = core .keySet ().iterator ();
358
- while (iterator .hasNext ()) {
359
- int m = iterator .next ();
360
- if (m > n ) {
361
- continue ;
362
- }
363
- R r = getByNumber (m );
364
- if (r != null ) {
365
- return r ;
366
- }
367
- }
368
- return null ;
369
- default :
370
- throw new AssertionError ();
339
+ if (d == EXACT ) {
340
+ return this .adapter .get (n );
371
341
}
342
+ // prepare sub map, where we need to find first resolvable entry
343
+ NavigableMap <Integer , BuildReference <R >> subCore = (d == ASC )
344
+ ? core .headMap (n , true ).descendingMap ()
345
+ : core .tailMap (n , true );
346
+ // wrap with BuildReferenceMapAdapter to skip unresolvable entries
347
+ return new BuildReferenceMapAdapter <>(subCore , buildResolver ).values ().stream ().findFirst ().orElse (null );
372
348
}
373
349
374
350
public R getById (String id ) {
375
351
return getByNumber (Integer .parseInt (id ));
376
352
}
377
353
378
354
/**
379
- * Ensure load referent object if needed, cache it and return
380
- * Save that object is unloadable in case of failure to avoid next load attempts
355
+ * Ensure loading referent object if needed, cache it and return
356
+ * Save that object as ' unloadable' in case of failure to avoid next load attempts
381
357
*
382
358
* @param ref reference object to be resolved
383
- * @return R referent build object, or null if can't be resolved
359
+ * @return R referent build object, or null if it can't be resolved
384
360
*/
385
361
private R resolveBuildRef (BuildReference <R > ref ) {
386
362
if (ref == null || ref .isUnloadable ()) {
@@ -551,5 +527,22 @@ public enum Direction {
551
527
ASC , DESC , EXACT
552
528
}
553
529
530
+ private class BuildReferenceMapAdapterResolver implements BuildReferenceMapAdapter .Resolver <R > {
531
+ @ Override
532
+ public R resolveBuildRef (BuildReference <R > buildRef ) {
533
+ return AbstractLazyLoadRunMap .this .resolveBuildRef (buildRef );
534
+ }
535
+
536
+ @ Override
537
+ public Integer getNumberOf (R build ) {
538
+ return AbstractLazyLoadRunMap .this .getNumberOf (build );
539
+ }
540
+
541
+ @ Override
542
+ public Class <R > getBuildClass () {
543
+ return AbstractLazyLoadRunMap .this .getBuildClass ();
544
+ }
545
+ }
546
+
554
547
static final Logger LOGGER = Logger .getLogger (AbstractLazyLoadRunMap .class .getName ());
555
548
}
0 commit comments