Skip to content

Commit

Permalink
Tidy up and fix handling of whiteboard GET calls
Browse files Browse the repository at this point in the history
Fixes eclipse#349

Signed-off-by: Tim Ward <timothyjward@apache.org>
  • Loading branch information
timothyjward committed Feb 12, 2024
1 parent 673d910 commit 68669a2
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import static java.util.stream.Collectors.toList;
import static java.util.stream.Stream.concat;
import static java.util.stream.Stream.empty;
import static java.util.stream.Stream.of;

import java.lang.annotation.Annotation;
Expand Down Expand Up @@ -57,9 +58,9 @@
import org.eclipse.sensinact.core.model.ResourceType;
import org.eclipse.sensinact.core.model.SensinactModelManager;
import org.eclipse.sensinact.core.model.Service;
import org.eclipse.sensinact.core.model.nexus.ModelNexus;
import org.eclipse.sensinact.core.twin.SensinactDigitalTwin;
import org.eclipse.sensinact.core.twin.TimedValue;
import org.eclipse.sensinact.core.model.nexus.ModelNexus;
import org.eclipse.sensinact.core.twin.impl.TimedValueImpl;
import org.osgi.framework.Constants;
import org.osgi.util.promise.Deferred;
Expand Down Expand Up @@ -300,15 +301,19 @@ private void handleActMethods(Long serviceId, Object service, Set<String> provid
}
}

static final class MethodHolder<A extends Annotation, RM extends AbstractResourceMethod> {
final A annotation;
final RM rcMethod;

public MethodHolder(A annotation, RM rcMethod) {
this.annotation = annotation;
this.rcMethod = rcMethod;
}
}

private void handlePullMethods(Long serviceId, Object service, Set<String> providers, List<Method> getMethods,
List<Method> setMethods) {
// We can find different behaviors for the handling of NullAction
final Map<NullAction, GetMethod> cachedMethod = new HashMap<>();

final class MethodHolder<A extends Annotation, RM extends AbstractResourceMethod> {
A annotation;
RM rcMethod;
}

// List the resources that are GET only, SET only or both
final Set<RegistryKey> resources = new LinkedHashSet<>();
Expand All @@ -317,64 +322,42 @@ final class MethodHolder<A extends Annotation, RM extends AbstractResourceMethod

// Walk GET-annotated methods
for (Method annotatedMethod : getMethods) {
if (annotatedMethod.isAnnotationPresent(GET.class)) {
final GET get = annotatedMethod.getAnnotation(GET.class);
// We can find different behaviors for the handling of NullAction
final Map<NullAction, GetMethod> cachedMethod = new HashMap<>();
Stream<GET> getStream = Optional.ofNullable(annotatedMethod.getAnnotation(GET.class))
.map(Stream::of).orElse(empty());

Stream<GET> getsStream = Optional.ofNullable(annotatedMethod.getAnnotation(GETs.class))
.map(GETs::value).map(Arrays::stream).orElse(empty());

Stream.concat(getStream, getsStream).forEach(get -> {
final RegistryKey key = new RegistryKey(get.modelPackageUri(), get.model(), get.service(), get.resource());
resources.add(key);

final GetMethod getMethod = cachedMethod.computeIfAbsent(get.onNull(),
(onNull) -> new GetMethod(annotatedMethod, service, serviceId, providers, onNull));

final MethodHolder<GET, GetMethod> getHolder = new MethodHolder<>();
getHolder.annotation = get;
getHolder.rcMethod = getMethod;
listGetMethods.computeIfAbsent(key, k -> new ArrayList<MethodHolder<GET, GetMethod>>()).add(getHolder);
}

if (annotatedMethod.isAnnotationPresent(GETs.class)) {
final GETs gets = annotatedMethod.getAnnotation(GETs.class);
for (GET get : gets.value()) {
final RegistryKey key = new RegistryKey(get.modelPackageUri(), get.model(), get.service(), get.resource());
resources.add(key);

final GetMethod getMethod = cachedMethod.computeIfAbsent(get.onNull(),
(onNull) -> new GetMethod(annotatedMethod, service, serviceId, providers, onNull));

final MethodHolder<GET, GetMethod> getHolder = new MethodHolder<>();
getHolder.annotation = get;
getHolder.rcMethod = getMethod;
listGetMethods.computeIfAbsent(key, k -> new ArrayList<MethodHolder<GET, GetMethod>>())
.add(getHolder);
}
}
listGetMethods.computeIfAbsent(key, k -> new ArrayList<>()).add(new MethodHolder<>(get, getMethod));
});
}

// Walk SET-annotated methods
for (Method annotatedMethod : setMethods) {
final SetMethod setMethod = new SetMethod(annotatedMethod, service, serviceId, providers);

if (annotatedMethod.isAnnotationPresent(SET.class)) {
final SET set = annotatedMethod.getAnnotation(SET.class);
Stream<SET> setStream = Optional.ofNullable(annotatedMethod.getAnnotation(SET.class))
.map(Stream::of).orElse(empty());

Stream<SET> setsStream = Optional.ofNullable(annotatedMethod.getAnnotation(SETs.class))
.map(SETs::value).map(Arrays::stream).orElse(empty());

Stream.concat(setStream, setsStream).forEach(set -> {
final RegistryKey key = new RegistryKey(set.modelPackageUri(), set.model(), set.service(), set.resource());
resources.add(key);

final MethodHolder<SET, SetMethod> setHolder = new MethodHolder<>();
setHolder.annotation = set;
setHolder.rcMethod = setMethod;
final MethodHolder<SET, SetMethod> setHolder = new MethodHolder<>(set, setMethod);
listSetMethods.computeIfAbsent(key, k -> new ArrayList<MethodHolder<SET, SetMethod>>()).add(setHolder);
}
if (annotatedMethod.isAnnotationPresent(SETs.class)) {
final SETs sets = annotatedMethod.getAnnotation(SETs.class);
for (SET set : sets.value()) {
final RegistryKey key = new RegistryKey(set.modelPackageUri(), set.model(), set.service(), set.resource());
resources.add(key);
final MethodHolder<SET, SetMethod> setHolder = new MethodHolder<>();
setHolder.annotation = set;
setHolder.rcMethod = setMethod;
listSetMethods.computeIfAbsent(key, k -> new ArrayList<MethodHolder<SET, SetMethod>>())
.add(setHolder);
}
}
});
}

for (final RegistryKey key : resources) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,4 +652,51 @@ void testPushPull() throws Throwable {
}
}
}

public static class TwoPullResourceTest {

@GET(model = "fizz", service = "buzz", resource = "version")
public String version() {
return "1.0.0";
}

@GET(model = "fizz", service = "buzz", resource = "count")
public Integer count() {
return 42;
}
}

@Nested
class TwoPullBasedResourceTest {

@Test
void testPushPull() throws Throwable {
TwoPullResourceTest resourceProvider = new TwoPullResourceTest();
thread.addWhiteboardService(resourceProvider,
Map.of("service.id", 259L, "sensiNact.whiteboard.resource", true));

final String svc = "buzz";
createProviders("fizz", svc);

runRcCommand(PROVIDER_A, svc, "version", (r) -> {
assertThrows(IllegalArgumentException.class, () -> r.getArguments());
return null;
});
runRcCommand(PROVIDER_A, svc, "count", (r) -> {
assertThrows(IllegalArgumentException.class, () -> r.getArguments());
return null;
});

// Initial values from the getter
TimedValue<String> result = getValue(PROVIDER_A, svc, "version", String.class);
assertNotNull(result.getValue(), "No value");
assertNotNull(result.getTimestamp(), "No timestamp");
assertEquals("1.0.0", result.getValue());

TimedValue<Integer> result2 = getValue(PROVIDER_A, svc, "count", Integer.class);
assertNotNull(result2.getValue(), "No value");
assertNotNull(result2.getTimestamp(), "No timestamp");
assertEquals(42, result2.getValue());
}
}
}

0 comments on commit 68669a2

Please sign in to comment.