diff --git a/distribution/features/northbound-rest-feature/pom.xml b/distribution/features/northbound-rest-feature/pom.xml
index 3f8c19bfe..d3949ccd9 100644
--- a/distribution/features/northbound-rest-feature/pom.xml
+++ b/distribution/features/northbound-rest-feature/pom.xml
@@ -26,6 +26,16 @@
filters.core
${rest.version}
+
+ org.eclipse.sensinact.gateway.filters
+ resource.selector
+ ${rest.version}
+
+
+ org.eclipse.sensinact.gateway.filters
+ resource.selector.impl
+ ${rest.version}
+
org.antlr
antlr4-runtime
diff --git a/distribution/features/northbound-rest-feature/src/main/resources/northbound-rest-feature.json b/distribution/features/northbound-rest-feature/src/main/resources/northbound-rest-feature.json
index 4396e3191..52377f566 100644
--- a/distribution/features/northbound-rest-feature/src/main/resources/northbound-rest-feature.json
+++ b/distribution/features/northbound-rest-feature/src/main/resources/northbound-rest-feature.json
@@ -3,6 +3,8 @@
"bundles":[
{ "id": "org.eclipse.sensinact.gateway.northbound:rest:${gateway.version}" },
{ "id": "org.eclipse.sensinact.gateway.filters:filters.core:${gateway.version}" },
+ { "id": "org.eclipse.sensinact.gateway.filters:resource.selector:${gateway.version}" },
+ { "id": "org.eclipse.sensinact.gateway.filters:resource.selector.impl:${gateway.version}" },
{ "id": "org.antlr:antlr4-runtime:4.12.0" },
{ "id": "org.eclipse.sensinact.gateway.filters:ldap:${gateway.version}" },
{ "id": "org.eclipse.sensinact.gateway.northbound:query-handler:${gateway.version}" },
diff --git a/northbound/query-handler/integration-test.bndrun b/northbound/query-handler/integration-test.bndrun
index 49b70b521..2ad14f6d0 100644
--- a/northbound/query-handler/integration-test.bndrun
+++ b/northbound/query-handler/integration-test.bndrun
@@ -42,6 +42,8 @@
org.eclipse.sensinact.gateway.core.models.metadata;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.core.models.provider;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.filters.filters.core;version='[0.0.2,0.0.3)',\
+ org.eclipse.sensinact.gateway.filters.resource.selector;version='[0.0.2,0.0.3)',\
+ org.eclipse.sensinact.gateway.filters.resource.selector.impl;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.northbound.query-handler;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.northbound.query-handler-tests;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.northbound.security.security-api;version='[0.0.2,0.0.3)',\
diff --git a/northbound/query-handler/pom.xml b/northbound/query-handler/pom.xml
index b131bdd5f..bfb6f4961 100644
--- a/northbound/query-handler/pom.xml
+++ b/northbound/query-handler/pom.xml
@@ -42,6 +42,11 @@
filters.core
${project.version}
+
+ org.eclipse.sensinact.gateway.filters
+ resource.selector
+ ${project.version}
+
@@ -81,6 +86,12 @@
${project.version}
test
+
+ org.eclipse.sensinact.gateway.filters
+ resource.selector.impl
+ ${project.version}
+ test
+
diff --git a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/AbstractResultDTO.java b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/AbstractResultDTO.java
index f77b84a8d..63ad4df0a 100644
--- a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/AbstractResultDTO.java
+++ b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/AbstractResultDTO.java
@@ -14,6 +14,7 @@
import org.eclipse.sensinact.northbound.query.dto.notification.ResultResourceNotificationDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ErrorResultDTO;
+import org.eclipse.sensinact.northbound.query.dto.result.ResponseSnapshotDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResultActDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResultDescribeProvidersDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResultListProvidersDTO;
@@ -40,6 +41,7 @@
@Type(value = ResultListProvidersDTO.class, name = "PROVIDERS_LIST"),
@Type(value = ResultListServicesDTO.class, name = "SERVICES_LIST"),
@Type(value = ResultListResourcesDTO.class, name = "RESOURCES_LIST"),
+ @Type(value = ResponseSnapshotDTO.class, name = "SNAPSHOT_RESPONSE"),
@Type(value = TypedResponse.class, names = { "DESCRIBE_PROVIDER", "DESCRIBE_SERVICE", "DESCRIBE_RESOURCE",
"GET_RESPONSE", "SET_RESPONSE" }),
@Type(value = ResultActDTO.class, name = "ACT_RESPONSE"),
diff --git a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/EQueryType.java b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/EQueryType.java
index a8cf721b5..f344c429a 100644
--- a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/EQueryType.java
+++ b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/EQueryType.java
@@ -38,6 +38,11 @@ public enum EQueryType {
*/
SET,
+ /**
+ * Get a snapshot
+ */
+ GET_SNAPSHOT,
+
/**
* Acts on a resource (path must describe a unique resource)
*/
diff --git a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/EResultType.java b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/EResultType.java
index f56aef089..c82517de4 100644
--- a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/EResultType.java
+++ b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/api/EResultType.java
@@ -22,6 +22,7 @@ public enum EResultType {
PROVIDERS_LIST,
SERVICES_LIST,
RESOURCES_LIST,
+ SNAPSHOT_RESPONSE,
DESCRIBE_PROVIDER,
DESCRIBE_SERVICE,
DESCRIBE_RESOURCE,
diff --git a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/query/QuerySnapshotDTO.java b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/query/QuerySnapshotDTO.java
new file mode 100644
index 000000000..d1331c22d
--- /dev/null
+++ b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/query/QuerySnapshotDTO.java
@@ -0,0 +1,36 @@
+/*********************************************************************
+* Copyright (c) 2023 Contributors to the Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Kentyou - initial implementation
+**********************************************************************/
+package org.eclipse.sensinact.northbound.query.dto.query;
+
+import java.util.List;
+
+import org.eclipse.sensinact.filters.resource.selector.api.ResourceSelector;
+import org.eclipse.sensinact.northbound.query.api.AbstractQueryDTO;
+import org.eclipse.sensinact.northbound.query.api.EQueryType;
+
+/**
+ *
+ */
+public class QuerySnapshotDTO extends AbstractQueryDTO {
+
+ /**
+ * If set, include metadata in the result
+ */
+ public boolean includeMetadata = false;
+
+ public List filter;
+
+ public QuerySnapshotDTO() {
+ super(EQueryType.GET_SNAPSHOT);
+ }
+}
diff --git a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/ResponseSnapshotDTO.java b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/ResponseSnapshotDTO.java
new file mode 100644
index 000000000..41ffda606
--- /dev/null
+++ b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/ResponseSnapshotDTO.java
@@ -0,0 +1,28 @@
+/*********************************************************************
+* Copyright (c) 2023 Contributors to the Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Kentyou - initial implementation
+**********************************************************************/
+package org.eclipse.sensinact.northbound.query.dto.result;
+
+import java.util.Map;
+
+import org.eclipse.sensinact.northbound.query.api.AbstractResultDTO;
+import org.eclipse.sensinact.northbound.query.api.EResultType;
+
+
+public class ResponseSnapshotDTO extends AbstractResultDTO {
+
+ public Map providers;
+
+ public ResponseSnapshotDTO() {
+ super(EResultType.SNAPSHOT_RESPONSE);
+ }
+}
diff --git a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/SnapshotProviderDTO.java b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/SnapshotProviderDTO.java
new file mode 100644
index 000000000..825a6054d
--- /dev/null
+++ b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/SnapshotProviderDTO.java
@@ -0,0 +1,33 @@
+/*********************************************************************
+* Copyright (c) 2022 Contributors to the Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Kentyou - initial implementation
+**********************************************************************/
+package org.eclipse.sensinact.northbound.query.dto.result;
+
+import java.util.Map;
+
+public class SnapshotProviderDTO {
+
+ /**
+ * Provider ID
+ */
+ public String name;
+
+ /**
+ * Model Name
+ */
+ public String modelName;
+
+ /**
+ * List of services
+ */
+ public Map services;
+}
diff --git a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/SnapshotResourceDTO.java b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/SnapshotResourceDTO.java
new file mode 100644
index 000000000..618fac53a
--- /dev/null
+++ b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/SnapshotResourceDTO.java
@@ -0,0 +1,47 @@
+/*********************************************************************
+* Copyright (c) 2023 Contributors to the Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Kentyou - initial implementation
+**********************************************************************/
+package org.eclipse.sensinact.northbound.query.dto.result;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+public class SnapshotResourceDTO {
+
+ /**
+ * Resource ID
+ */
+ public String name;
+
+ /**
+ * Value milliseconds timestamp
+ */
+ public long timestamp;
+
+ /**
+ * Value type
+ */
+ public String type;
+
+ /**
+ * Value value
+ */
+ public Object value;
+
+ /**
+ * Metadata, if requested
+ */
+ @JsonInclude(Include.NON_NULL)
+ public List attributes;
+}
diff --git a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/SnapshotServiceDTO.java b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/SnapshotServiceDTO.java
new file mode 100644
index 000000000..882bf0a5d
--- /dev/null
+++ b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/dto/result/SnapshotServiceDTO.java
@@ -0,0 +1,28 @@
+/*********************************************************************
+* Copyright (c) 2022 Contributors to the Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Kentyou - initial implementation
+**********************************************************************/
+package org.eclipse.sensinact.northbound.query.dto.result;
+
+import java.util.Map;
+
+public class SnapshotServiceDTO {
+
+ /**
+ * Provider ID
+ */
+ public String name;
+
+ /**
+ * List of resources
+ */
+ public Map resources;
+}
diff --git a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/impl/QueryHandler.java b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/impl/QueryHandler.java
index 7c7a28f14..97584c846 100644
--- a/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/impl/QueryHandler.java
+++ b/northbound/query-handler/src/main/java/org/eclipse/sensinact/northbound/query/impl/QueryHandler.java
@@ -15,6 +15,7 @@
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -39,6 +40,7 @@
import org.eclipse.sensinact.filters.api.FilterCommandHelper;
import org.eclipse.sensinact.filters.api.FilterException;
import org.eclipse.sensinact.filters.api.IFilterHandler;
+import org.eclipse.sensinact.filters.resource.selector.api.ResourceSelectorFilterFactory;
import org.eclipse.sensinact.gateway.geojson.GeoJsonObject;
import org.eclipse.sensinact.northbound.query.api.AbstractQueryDTO;
import org.eclipse.sensinact.northbound.query.api.AbstractResultDTO;
@@ -52,6 +54,7 @@
import org.eclipse.sensinact.northbound.query.dto.query.QueryGetDTO;
import org.eclipse.sensinact.northbound.query.dto.query.QueryListDTO;
import org.eclipse.sensinact.northbound.query.dto.query.QuerySetDTO;
+import org.eclipse.sensinact.northbound.query.dto.query.QuerySnapshotDTO;
import org.eclipse.sensinact.northbound.query.dto.result.AccessMethodDTO;
import org.eclipse.sensinact.northbound.query.dto.result.AccessMethodParameterDTO;
import org.eclipse.sensinact.northbound.query.dto.result.CompleteProviderDescriptionDTO;
@@ -62,12 +65,16 @@
import org.eclipse.sensinact.northbound.query.dto.result.ResponseDescribeServiceDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResponseGetDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResponseSetDTO;
+import org.eclipse.sensinact.northbound.query.dto.result.ResponseSnapshotDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResultActDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResultDescribeProvidersDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResultListProvidersDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResultListResourcesDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ResultListServicesDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ShortResourceDescriptionDTO;
+import org.eclipse.sensinact.northbound.query.dto.result.SnapshotProviderDTO;
+import org.eclipse.sensinact.northbound.query.dto.result.SnapshotResourceDTO;
+import org.eclipse.sensinact.northbound.query.dto.result.SnapshotServiceDTO;
import org.eclipse.sensinact.northbound.query.dto.result.TypedResponse;
import org.eclipse.sensinact.northbound.session.ProviderDescription;
import org.eclipse.sensinact.northbound.session.ResourceDescription;
@@ -103,6 +110,9 @@ public class QueryHandler implements IQueryHandler {
@Reference
GatewayThread gatewayThread;
+ @Reference
+ ResourceSelectorFilterFactory resourceSelectorFilterFactory;
+
/**
* Current filter handler
*/
@@ -147,6 +157,10 @@ public AbstractResultDTO handleQuery(final SensiNactSession userSession, final A
result = handleAct(userSession, (QueryActDTO) query);
break;
+ case GET_SNAPSHOT:
+ result = handleSnapshot(userSession, (QuerySnapshotDTO) query);
+ break;
+
default:
result = new ErrorResultDTO(501, "Operation not implemented");
break;
@@ -362,14 +376,77 @@ private AbstractResultDTO handleAct(final SensiNactSession userSession, final Qu
*/
private Collection executeFilter(final String filter, final String filterLanguage)
throws StatusException {
- final ICriterion parsedFilter = parseFilter(filter, filterLanguage);
+ return executeFilter(parseFilter(filter, filterLanguage));
+ }
+
+ /**
+ * Executes the given parser
+ *
+ * @param filter Filter
+ * @return Matching snapshot
+ * @throws StatusException Error parsing or executing filter
+ */
+ private Collection executeFilter(final ICriterion filter)
+ throws StatusException {
try {
- return FilterCommandHelper.executeFilter(gatewayThread, parsedFilter);
+ return FilterCommandHelper.executeFilter(gatewayThread, filter);
} catch (FilterException e) {
throw new StatusException(500, "Error executing filter: " + e.getMessage());
}
}
+ /**
+ * Root of snapshot handling
+ *
+ * @param userSession Caller session
+ * @param query Query description
+ * @return Result DTO
+ */
+ private AbstractResultDTO handleSnapshot(final SensiNactSession userSession, final QuerySnapshotDTO query)
+ throws Exception {
+ final ResponseSnapshotDTO result = new ResponseSnapshotDTO();
+
+ result.providers = new HashMap<>();
+ result.uri = "/";
+ result.statusCode = 200;
+
+ for (var filter: query.filter) {
+ ICriterion criterion = resourceSelectorFilterFactory.parseResourceSelector(filter);
+ for (var providerSnapshot: executeFilter(criterion)) {
+ for (var serviceSnapshot: providerSnapshot.getServices()) {
+ for (var resourceSnapshot: serviceSnapshot.getResources()) {
+ if (resourceSnapshot.getValue() != null) {
+ SnapshotProviderDTO providerDTO = result.providers.computeIfAbsent(providerSnapshot.getName(), (name) -> {
+ var dto = new SnapshotProviderDTO();
+ dto.name = providerSnapshot.getName();
+ dto.modelName = providerSnapshot.getModelName();
+ dto.services = new HashMap<>();
+ return dto;
+ });
+ SnapshotServiceDTO serviceDTO = providerDTO.services.computeIfAbsent(serviceSnapshot.getName(), (name) -> {
+ var dto = new SnapshotServiceDTO();
+ dto.name = serviceSnapshot.getName();
+ dto.resources = new HashMap<>();
+ return dto;
+ });
+ SnapshotResourceDTO resourceDTO = new SnapshotResourceDTO();
+ resourceDTO.name = resourceSnapshot.getName();
+ resourceDTO.type = resourceSnapshot.getType().getName();
+ resourceDTO.timestamp = resourceSnapshot.getValue().getTimestamp().toEpochMilli();
+ resourceDTO.value = resourceSnapshot.getValue().getValue();
+ if (query.includeMetadata) {
+ resourceDTO.attributes = generateMetadataDescriptions(resourceSnapshot.getMetadata());
+ }
+ serviceDTO.resources.put(resourceSnapshot.getName(), resourceDTO);
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
/**
* Lists the providers
*
diff --git a/northbound/rest/integration-test.bndrun b/northbound/rest/integration-test.bndrun
index 39bd2a429..8aed81d44 100644
--- a/northbound/rest/integration-test.bndrun
+++ b/northbound/rest/integration-test.bndrun
@@ -58,6 +58,7 @@
org.eclipse.emf.common;version='[2.29.0,2.29.1)',\
org.eclipse.emf.ecore;version='[2.35.0,2.35.1)',\
org.eclipse.emf.ecore.xmi;version='[2.36.0,2.36.1)',\
+ org.eclipse.jetty.http;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.io;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.security;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.server;version='[11.0.13,11.0.14)',\
@@ -75,6 +76,8 @@
org.eclipse.sensinact.gateway.core.models.provider;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.filters.filters.core;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.filters.ldap;version='[0.0.2,0.0.3)',\
+ org.eclipse.sensinact.gateway.filters.resource.selector;version='[0.0.2,0.0.3)',\
+ org.eclipse.sensinact.gateway.filters.resource.selector.impl;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.northbound.query-handler;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.northbound.rest;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.northbound.rest-tests;version='[0.0.2,0.0.3)',\
diff --git a/northbound/rest/pom.xml b/northbound/rest/pom.xml
index 6b125fecc..05d354360 100644
--- a/northbound/rest/pom.xml
+++ b/northbound/rest/pom.xml
@@ -32,6 +32,11 @@
session-api
${project.version}
+
+ org.eclipse.sensinact.gateway.filters
+ resource.selector
+ ${project.version}
+
org.eclipse.sensinact.gateway.core
geo-json
@@ -92,6 +97,12 @@
${project.version}
test
+
+ org.eclipse.sensinact.gateway.filters
+ resource.selector.impl
+ ${project.version}
+ test
+
org.eclipse.sensinact.gateway.northbound.session
session-impl
diff --git a/northbound/rest/src/main/java/org/eclipse/sensinact/northbound/rest/api/IRestNorthbound.java b/northbound/rest/src/main/java/org/eclipse/sensinact/northbound/rest/api/IRestNorthbound.java
index df89c19eb..fc97040fc 100644
--- a/northbound/rest/src/main/java/org/eclipse/sensinact/northbound/rest/api/IRestNorthbound.java
+++ b/northbound/rest/src/main/java/org/eclipse/sensinact/northbound/rest/api/IRestNorthbound.java
@@ -14,6 +14,9 @@
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
+import java.util.List;
+
+import org.eclipse.sensinact.filters.resource.selector.api.ResourceSelector;
import org.eclipse.sensinact.northbound.query.api.AbstractResultDTO;
import org.eclipse.sensinact.northbound.query.dto.query.WrappedAccessMethodCallParametersDTO;
@@ -36,6 +39,10 @@ public interface IRestNorthbound {
@GET
AbstractResultDTO describeProviders();
+ @Path("snapshot")
+ @POST
+ AbstractResultDTO getSnapshot(@QueryParam("metadata") @DefaultValue("false") boolean includeMetadata, List filter);
+
@Path("providers")
@GET
AbstractResultDTO listProviders();
diff --git a/northbound/rest/src/main/java/org/eclipse/sensinact/northbound/rest/impl/RestNorthbound.java b/northbound/rest/src/main/java/org/eclipse/sensinact/northbound/rest/impl/RestNorthbound.java
index 1e7d7737b..6f8239566 100644
--- a/northbound/rest/src/main/java/org/eclipse/sensinact/northbound/rest/impl/RestNorthbound.java
+++ b/northbound/rest/src/main/java/org/eclipse/sensinact/northbound/rest/impl/RestNorthbound.java
@@ -22,6 +22,7 @@
import org.eclipse.sensinact.core.notification.AbstractResourceNotification;
import org.eclipse.sensinact.core.notification.ClientDataListener;
import org.eclipse.sensinact.core.notification.ClientLifecycleListener;
+import org.eclipse.sensinact.filters.resource.selector.api.ResourceSelector;
import org.eclipse.sensinact.northbound.query.api.AbstractQueryDTO;
import org.eclipse.sensinact.northbound.query.api.AbstractResultDTO;
import org.eclipse.sensinact.northbound.query.api.IQueryHandler;
@@ -34,6 +35,7 @@
import org.eclipse.sensinact.northbound.query.dto.query.QueryGetDTO;
import org.eclipse.sensinact.northbound.query.dto.query.QueryListDTO;
import org.eclipse.sensinact.northbound.query.dto.query.QuerySetDTO;
+import org.eclipse.sensinact.northbound.query.dto.query.QuerySnapshotDTO;
import org.eclipse.sensinact.northbound.query.dto.query.WrappedAccessMethodCallParametersDTO;
import org.eclipse.sensinact.northbound.query.dto.result.ErrorResultDTO;
import org.eclipse.sensinact.northbound.rest.api.IRestNorthbound;
@@ -193,6 +195,15 @@ public AbstractResultDTO resourceGet(final String providerId, final String servi
return handleQuery(query);
}
+ @Override
+ public AbstractResultDTO getSnapshot(final boolean includeMetadata, List filter) {
+ final QuerySnapshotDTO query = new QuerySnapshotDTO();
+ query.uri = new SensinactPath();
+ query.filter = filter;
+ query.includeMetadata = includeMetadata;
+ return handleQuery(query);
+ }
+
/**
* Extract the new value to set to a resource according to the given arguments
*
diff --git a/northbound/rest/src/test/java/org/eclipse/sensinact/northbound/rest/integration/ResourceSnapshotTest.java b/northbound/rest/src/test/java/org/eclipse/sensinact/northbound/rest/integration/ResourceSnapshotTest.java
new file mode 100644
index 000000000..d0739c1ca
--- /dev/null
+++ b/northbound/rest/src/test/java/org/eclipse/sensinact/northbound/rest/integration/ResourceSnapshotTest.java
@@ -0,0 +1,125 @@
+/*********************************************************************
+* Copyright (c) 2022 Contributors to the Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Kentyou - initial implementation
+**********************************************************************/
+package org.eclipse.sensinact.northbound.rest.integration;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+
+import org.eclipse.sensinact.core.notification.ResourceDataNotification;
+import org.eclipse.sensinact.core.push.DataUpdate;
+import org.eclipse.sensinact.core.push.dto.GenericDto;
+import org.eclipse.sensinact.filters.resource.selector.api.ResourceSelector;
+import org.eclipse.sensinact.filters.resource.selector.api.Selection;
+import org.eclipse.sensinact.northbound.query.dto.result.ResponseSnapshotDTO;
+import org.eclipse.sensinact.northbound.query.dto.result.SnapshotProviderDTO;
+import org.eclipse.sensinact.northbound.query.dto.result.SnapshotResourceDTO;
+import org.eclipse.sensinact.northbound.query.dto.result.SnapshotServiceDTO;
+import org.eclipse.sensinact.northbound.security.api.UserInfo;
+import org.eclipse.sensinact.northbound.session.SensiNactSession;
+import org.eclipse.sensinact.northbound.session.SensiNactSessionManager;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.opentest4j.AssertionFailedError;
+import org.osgi.service.cm.Configuration;
+import org.osgi.test.common.annotation.InjectService;
+import org.osgi.test.common.annotation.Property;
+import org.osgi.test.common.annotation.config.InjectConfiguration;
+import org.osgi.test.common.annotation.config.WithConfiguration;
+import org.osgi.test.common.service.ServiceAware;
+
+import jakarta.ws.rs.core.Application;
+
+@WithConfiguration(pid = "sensinact.session.manager", properties = @Property(key = "auth.policy", value = "ALLOW_ALL"))
+public class ResourceSnapshotTest {
+
+ @BeforeEach
+ public void await(
+ @InjectConfiguration(withConfig = @WithConfiguration(pid = "sensinact.northbound.rest", location = "?", properties = {
+ @Property(key = "allow.anonymous", value = "true"),
+ @Property(key = "foobar", value = "fizz") })) Configuration cm,
+ @InjectService(filter = "(foobar=fizz)", cardinality = 0) ServiceAware a)
+ throws InterruptedException {
+ a.waitForService(5000);
+ for (int i = 0; i < 10; i++) {
+ try {
+ if (utils.queryStatus("/").statusCode() == 200)
+ return;
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ Thread.sleep(200);
+ }
+ throw new AssertionFailedError("REST API did not appear");
+ }
+
+ private static final UserInfo USER = UserInfo.ANONYMOUS;
+
+ @InjectService
+ SensiNactSessionManager sessionManager;
+
+ @InjectService
+ DataUpdate push;
+
+ BlockingQueue queue;
+
+ final TestUtils utils = new TestUtils();
+
+ @AfterEach
+ void stop() {
+ if (queue != null) {
+ SensiNactSession session = sessionManager.getDefaultSession(USER);
+ session.activeListeners().keySet().forEach(session::removeListener);
+ queue = null;
+ }
+ }
+
+ /**
+ * Get the resource value
+ */
+ @Test
+ void resourceGetSnapshot() throws Exception {
+ // Register the resource
+ GenericDto dto = utils.makeDto("M1", "P1", "S1", "R1", "V1", String.class);
+ Instant updateTime = Instant.now().truncatedTo(ChronoUnit.MILLIS);
+ push.pushUpdate(dto).getValue();
+
+ List request = new ArrayList<>();
+ ResourceSelector rs = new ResourceSelector();
+ rs.model = new Selection();
+ rs.model.value = "M1";
+ rs.service = new Selection();
+ rs.service.value = "S1";
+ request.add(rs);
+ ResponseSnapshotDTO response = utils.queryJson("snapshot", request, ResponseSnapshotDTO.class);
+
+ assertEquals(1, response.providers.size());
+ SnapshotProviderDTO providerDTO = response.providers.get("P1");
+ assertEquals("P1", providerDTO.name);
+ assertEquals("M1", providerDTO.modelName);
+ assertEquals(1, providerDTO.services.size());
+ SnapshotServiceDTO serviceDTO = providerDTO.services.get("S1");
+ assertEquals("S1", serviceDTO.name);
+ assertEquals(1, serviceDTO.resources.size());
+ SnapshotResourceDTO resourceDTO = serviceDTO.resources.get("R1");
+ assertEquals("R1", resourceDTO.name);
+ assertEquals("java.lang.String", resourceDTO.type);
+ assertEquals("V1", resourceDTO.value);
+ }
+}
diff --git a/northbound/sensorthings/rest.gateway/integration-test.bndrun b/northbound/sensorthings/rest.gateway/integration-test.bndrun
index f3a36e382..d1c8720a7 100644
--- a/northbound/sensorthings/rest.gateway/integration-test.bndrun
+++ b/northbound/sensorthings/rest.gateway/integration-test.bndrun
@@ -61,6 +61,7 @@
org.eclipse.emf.common;version='[2.29.0,2.29.1)',\
org.eclipse.emf.ecore;version='[2.35.0,2.35.1)',\
org.eclipse.emf.ecore.xmi;version='[2.36.0,2.36.1)',\
+ org.eclipse.jetty.http;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.io;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.security;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.server;version='[11.0.13,11.0.14)',\
diff --git a/northbound/websocket/integration-test.bndrun b/northbound/websocket/integration-test.bndrun
index 2bedfdb13..d8f91e02d 100644
--- a/northbound/websocket/integration-test.bndrun
+++ b/northbound/websocket/integration-test.bndrun
@@ -52,11 +52,15 @@
org.eclipse.emf.ecore.xmi;version='[2.36.0,2.36.1)',\
org.eclipse.jetty.alpn.client;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.client;version='[11.0.13,11.0.14)',\
+ org.eclipse.jetty.http;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.io;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.jndi;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.plus;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.security;version='[11.0.13,11.0.14)',\
+ org.eclipse.jetty.server;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.servlet;version='[11.0.13,11.0.14)',\
+ org.eclipse.jetty.servlet-api;version='[5.0.2,5.0.3)',\
+ org.eclipse.jetty.util;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.webapp;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.websocket.api;version='[11.0.13,11.0.14)',\
org.eclipse.jetty.websocket.client;version='[11.0.13,11.0.14)',\
@@ -77,6 +81,8 @@
org.eclipse.sensinact.gateway.core.models.provider;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.filters.filters.core;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.filters.ldap;version='[0.0.2,0.0.3)',\
+ org.eclipse.sensinact.gateway.filters.resource.selector;version='[0.0.2,0.0.3)',\
+ org.eclipse.sensinact.gateway.filters.resource.selector.impl;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.northbound.query-handler;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.northbound.security.security-api;version='[0.0.2,0.0.3)',\
org.eclipse.sensinact.gateway.northbound.session.session-api;version='[0.0.2,0.0.3)',\
diff --git a/northbound/websocket/pom.xml b/northbound/websocket/pom.xml
index ff4e5a126..225a53c61 100644
--- a/northbound/websocket/pom.xml
+++ b/northbound/websocket/pom.xml
@@ -93,6 +93,12 @@
${project.version}
test
+
+ org.eclipse.sensinact.gateway.filters
+ resource.selector.impl
+ ${project.version}
+ test
+
org.osgi
org.osgi.test.junit5.cm