Skip to content

Commit 49228d7

Browse files
committed
ServiceIndex: add getPrev, getNext API
Added convenience methods for accessing lower and higher priority services relative to a specified base service.
1 parent 98b1079 commit 49228d7

File tree

2 files changed

+147
-2
lines changed

2 files changed

+147
-2
lines changed

src/main/java/org/scijava/service/ServiceIndex.java

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131

3232
package org.scijava.service;
3333

34-
3534
import java.util.List;
3635

3736
import org.scijava.object.SortedObjectIndex;
@@ -51,10 +50,77 @@ public ServiceIndex() {
5150

5251
/** Gets the first available service compatible with the given class. */
5352
public <S extends Service> S getService(final Class<S> c) {
53+
return getService(c, null, 0);
54+
}
55+
56+
/**
57+
* Gets the highest priority service compatible with class {@code c}, which is
58+
* lower priority than the {@code ref} service.
59+
*/
60+
public <S extends Service> S getNextService(final Class<S> c,
61+
final Class<? extends S> ref)
62+
{
63+
return getService(c, ref, 1);
64+
}
65+
66+
/**
67+
* Gets the lowest priority service compatible with class {@code c}, which is
68+
* higher priority than the {@code ref} service.
69+
*/
70+
public <S extends Service> S getPrevService(final Class<S> c,
71+
final Class<? extends S> ref)
72+
{
73+
return getService(c, ref, -1);
74+
}
75+
76+
// -- Helper methods --
77+
78+
/**
79+
* Gets the service compatible with the base class {@code c}, with the
80+
* modified priority relative to the given reference service, or the highest
81+
* priority service if no reference is given.
82+
*
83+
* @param c - Base class to find compatible services
84+
* @param ref - Reference service class for priority comparisons. If null,
85+
* highest priority service is returned.
86+
* @param priorityMod - Relative priority value. If {@code ref} is non-null,
87+
* this value is applied to the {@code ref} service's index in the
88+
* list of compatible services to determine the returned service. For
89+
* example, a value of +1 will return the next lowest priority
90+
* service, and a value of -1 will return the next highest priority
91+
* service - as the services are sorted from highest to lowest
92+
* priority.
93+
* @return Service matching the given criteria, or null if no applicable
94+
* service.
95+
*/
96+
private <S extends Service> S getService(final Class<S> c,
97+
final Class<? extends S> ref, final int priorityMod)
98+
{
5499
final List<Service> list = get(c);
55100
if (list.isEmpty()) return null;
101+
102+
int index = 0;
103+
104+
if (ref != null) {
105+
// find the ref class's index
106+
for (; index < list.size() && !list.get(index).getClass().equals(ref); index++)
107+
{}
108+
109+
// ref class wasn't on the list
110+
if (index == list.size()) return null;
111+
112+
// Update the index for the desired relative priority
113+
index += priorityMod;
114+
}
115+
116+
// If the priorityMod took the index outside the list bounds, then there is
117+
// no appropriate
118+
// service to return.
119+
if (index < 0 || index >= list.size()) return null;
120+
56121
@SuppressWarnings("unchecked")
57-
final S service = (S) list.get(0);
122+
final S service = (S) list.get(index);
123+
58124
return service;
59125
}
60126

src/test/java/org/scijava/service/ServiceIndexTest.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
package org.scijava.service;
3333

3434
import static org.junit.Assert.assertEquals;
35+
import static org.junit.Assert.assertNull;
3536
import static org.junit.Assert.assertSame;
3637

3738
import java.util.List;
@@ -40,6 +41,8 @@
4041
import org.scijava.Context;
4142
import org.scijava.event.DefaultEventService;
4243
import org.scijava.log.StderrLogService;
44+
import org.scijava.options.DefaultOptionsService;
45+
import org.scijava.options.OptionsService;
4346
import org.scijava.plugin.DefaultPluginService;
4447
import org.scijava.plugin.PluginService;
4548
import org.scijava.thread.DefaultThreadService;
@@ -63,4 +66,80 @@ public void testGetAll() {
6366
assertSame(StderrLogService.class, all.get(3).getClass());
6467
}
6568

69+
/**
70+
* Test the {@link ServiceIndex#getPrevService(Class, Class)} operation.
71+
*/
72+
@Test
73+
public void testGetPrevService() {
74+
// Create a service index where the OptionsService hierarchy should be:
75+
// HigherOptionsService > DefaultOptionsService > LowerOptionsService
76+
final ServiceIndex serviceIndex = setUpPrivateServices();
77+
78+
// DefaultOptionsService should be the previous service to LowerOptionsService
79+
assertEquals(DefaultOptionsService.class, serviceIndex.getPrevService(
80+
OptionsService.class, LowerOptionsService.class).getClass());
81+
82+
// HigherOptionsService should be the previous service to
83+
// DefaultOptionsService
84+
assertEquals(HigherOptionsService.class, serviceIndex.getPrevService(
85+
OptionsService.class, DefaultOptionsService.class).getClass());
86+
87+
// There should not be a previous service before HigherOptionsService
88+
assertNull(serviceIndex.getPrevService(OptionsService.class,
89+
HigherOptionsService.class));
90+
}
91+
92+
/**
93+
* Test the {@link ServiceIndex#getNextService(Class, Class)} operation.
94+
*/
95+
@Test
96+
public void testGetNextService() {
97+
// Create a service index where the OptionsService hierarchy should be:
98+
// HigherOptionService > DefaultOptionService > LowerOptionService
99+
final ServiceIndex serviceIndex = setUpPrivateServices();
100+
101+
// DefaultOptionsService should be the next service to HigherOptionsService
102+
assertEquals(DefaultOptionsService.class, serviceIndex.getNextService(
103+
OptionsService.class, HigherOptionsService.class).getClass());
104+
105+
// HigherOptionsService should be the previous service to
106+
// DefaultOptionsService
107+
assertEquals(LowerOptionsService.class, serviceIndex.getNextService(
108+
OptionsService.class, DefaultOptionsService.class).getClass());
109+
110+
// There should not be a next service after LowerOptionsService
111+
assertNull(serviceIndex.getNextService(OptionsService.class,
112+
LowerOptionsService.class));
113+
}
114+
115+
// -- Helper methods --
116+
117+
/**
118+
* @return A {@link ServiceIndex} with all private services manually added.
119+
*/
120+
private ServiceIndex setUpPrivateServices() {
121+
final Context context = new Context(SciJavaService.class);
122+
final ServiceIndex serviceIndex = context.getServiceIndex();
123+
serviceIndex.add(new HigherOptionsService());
124+
serviceIndex.add(new LowerOptionsService());
125+
return serviceIndex;
126+
}
127+
128+
// -- Private services --
129+
130+
private static class HigherOptionsService extends DefaultOptionsService {
131+
132+
@Override
133+
public double getPriority() {
134+
return super.getPriority() + 25;
135+
}
136+
}
137+
138+
private static class LowerOptionsService extends DefaultOptionsService {
139+
140+
@Override
141+
public double getPriority() {
142+
return super.getPriority() - 30;
143+
}
144+
}
66145
}

0 commit comments

Comments
 (0)