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