Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,12 @@
import org.sensorhub.api.data.IObsData;
import org.sensorhub.api.procedure.IProcedureWithDesc;
import org.sensorhub.api.semantic.IDerivedProperty;
import org.sensorhub.api.system.IDeploymentWithDesc;
import org.sensorhub.api.system.ISystemWithDesc;
import org.sensorhub.impl.common.IdEncodersBase32;
import org.sensorhub.impl.service.consys.ResourceParseException;
import org.sensorhub.impl.service.consys.deployment.DeploymentBindingGeoJson;
import org.sensorhub.impl.service.consys.deployment.DeploymentBindingSmlJson;
import org.sensorhub.impl.service.consys.feature.FoiBindingGeoJson;
import org.sensorhub.impl.service.consys.obs.DataStreamBindingJson;
import org.sensorhub.impl.service.consys.obs.DataStreamSchemaBindingOmJson;
Expand Down Expand Up @@ -526,6 +529,97 @@ protected void endJsonCollection(JsonWriter writer, Collection<ResourceLink> lin
}
}

/*-------------*/
/* Deployments */
/*-------------*/

public CompletableFuture<IDeploymentWithDesc> getDeploymentById(String id, ResourceFormat format)
{
return sendGetRequest(endpoint.resolve(DEPLOYMENTS_COLLECTION + "/" + urlPathEncode(id)), format, body -> {
try
{
var ctx = new RequestContext(body);
var binding = new DeploymentBindingGeoJson(ctx, null, null, true);
return binding.deserialize();
}
catch (IOException e)
{
e.printStackTrace();
throw new CompletionException(e);
}
});
}

public CompletableFuture<IDeploymentWithDesc> getDeploymentByUid(String uid, ResourceFormat format)
{
return sendGetRequest(endpoint.resolve(DEPLOYMENTS_COLLECTION + "?id=" + urlQueryEncode(uid)), format, body -> {
try
{
var ctx = new RequestContext(body);

// use modified binding since the response contains a feature collection
var binding = new DeploymentBindingGeoJson(ctx, null, null, true) {
protected JsonReader getJsonReader(InputStream is) throws IOException
{
var reader = super.getJsonReader(is);
skipToCollectionItems(reader);
return reader;
}
};

return binding.deserialize();
}
catch (IOException e)
{
e.printStackTrace();
throw new CompletionException(e);
}
});
}

public CompletableFuture<String> addDeployment(IDeploymentWithDesc deployment)
{
try
{
var buffer = new ByteArrayOutputStream();
var ctx = new RequestContext(buffer);

var binding = new DeploymentBindingSmlJson(ctx, null, false);
binding.serialize(null, deployment, false);

return sendPostRequest(
endpoint.resolve(DEPLOYMENTS_COLLECTION),
ResourceFormat.SML_JSON,
buffer.toByteArray());
}
catch (IOException e)
{
throw new IllegalStateException("Error initializing deployment binding", e);
}
}


public CompletableFuture<Integer> updateDeployment(String deploymentID, IDeploymentWithDesc deployment)
{
try
{
var buffer = new ByteArrayOutputStream();
var ctx = new RequestContext(buffer);

var binding = new DeploymentBindingSmlJson(ctx, null, false);
binding.serialize(null, deployment, false);

return sendPutRequest(
endpoint.resolve(DEPLOYMENTS_COLLECTION + "/" + deploymentID),
ResourceFormat.SML_JSON,
buffer.toByteArray());
}
catch (IOException e)
{
throw new IllegalStateException("Error initializing deployment binding", e);
}
}

/*-------------------*/
/* Sampling Features */
/*-------------------*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.sensorhub.api.system.SystemRemovedEvent;
import org.sensorhub.api.system.SystemDisabledEvent;
import org.sensorhub.api.system.SystemEvent;
import org.sensorhub.api.system.IDeploymentWithDesc;
import org.sensorhub.impl.module.AbstractModule;
import org.sensorhub.impl.security.ClientAuth;
import org.sensorhub.impl.service.consys.resource.ResourceFormat;
Expand All @@ -41,6 +42,7 @@ public class ConSysApiClientModule extends AbstractModule<ConSysApiClientConfig>
String apiEndpointUrl;
ConSysApiClient client;
Map<String, SystemRegInfo> registeredSystems;
Map<BigId, DeploymentRegInfo> registeredDeployments;
Map<BigId, String> registeredFeatureIDs;
NavigableMap<String, StreamInfo> dataStreams;
Flow.Subscription registrySubscription;
Expand All @@ -53,6 +55,13 @@ public static class SystemRegInfo
private ISystemWithDesc system;
}

public static class DeploymentRegInfo
{
private String deploymentID;
private BigId internalID;
private IDeploymentWithDesc deployment;
}

public static class StreamInfo
{
private IDataStreamInfo dataStream;
Expand All @@ -66,6 +75,7 @@ public static class StreamInfo
public ConSysApiClientModule()
{
this.registeredSystems = new ConcurrentHashMap<>();
this.registeredDeployments = new ConcurrentHashMap<>();
this.registeredFeatureIDs = new ConcurrentHashMap<>();
this.dataStreams = new ConcurrentSkipListMap<>();
}
Expand Down Expand Up @@ -130,6 +140,10 @@ protected void doStart() throws SensorHubException {
registerSystemDataStreams(systemRegInfo);
});

dataBaseView.getDeploymentStore().selectEntries(
dataBaseView.getDeploymentStore().selectAllFilter())
.forEach(entry -> registerDeployment(entry.getKey().getInternalID(), entry.getValue()));

dataBaseView.getFoiStore().selectEntries(
dataBaseView.getFoiStore().selectAllFilter())
.forEach(entry -> registerSamplingFeature(entry.getKey(), entry.getValue()));
Expand Down Expand Up @@ -207,6 +221,24 @@ private String tryUpdateSystem(ISystemWithDesc system)
return null;
}

private String tryUpdateDeployment(IDeploymentWithDesc deployment)
{
try {
var oldDeployment = client.getDeploymentByUid(deployment.getUniqueIdentifier(), ResourceFormat.JSON).get();
if (oldDeployment != null) {
var deploymentID = oldDeployment.getId();
var responseCode = client.updateDeployment(deploymentID, deployment).get();
if (responseCode != HttpURLConnection.HTTP_NO_CONTENT)
throw new ClientException("Failed to update resource: " +
apiEndpointUrl + ConSysApiClient.DEPLOYMENTS_COLLECTION + "/" + deploymentID);
return deploymentID;
}
} catch (ExecutionException | InterruptedException | ClientException e) {
throw new RuntimeException(e);
}
return null;
}

private String tryUpdateSamplingFeature(IFeature feature)
{
try {
Expand Down Expand Up @@ -260,6 +292,18 @@ protected SystemRegInfo registerSystem(BigId systemInternalID, ISystemWithDesc s
}
}

protected DeploymentRegInfo registerDeployment(BigId deploymentInternalID, IDeploymentWithDesc deployment) {
try {
String deploymentID = tryUpdateDeployment(deployment);
if(deploymentID == null)
deploymentID = client.addDeployment(deployment).get();

return registerDeploymentInfo(deploymentID, deploymentInternalID, deployment);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}

protected void registerSamplingFeature(BigId featureInternalId, String systemId, IFeature feature)
{
try {
Expand Down Expand Up @@ -312,6 +356,16 @@ private SystemRegInfo registerSystemInfo(String systemID, BigId systemInternalID
return systemRegInfo;
}

private DeploymentRegInfo registerDeploymentInfo(String deploymentID, BigId deploymentInternalID, IDeploymentWithDesc deployment) {
DeploymentRegInfo deploymentRegInfo = new DeploymentRegInfo();
deploymentRegInfo.deploymentID = deploymentID;
deploymentRegInfo.internalID = deploymentInternalID;
deploymentRegInfo.deployment = deployment;

registeredDeployments.put(deploymentInternalID, deploymentRegInfo);
return deploymentRegInfo;
}

protected List<StreamInfo> registerSystemDataStreams(SystemRegInfo system)
{
List<StreamInfo> addedStreams = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/***************************** BEGIN LICENSE BLOCK ***************************

The contents of this file are subject to the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.

Copyright (C) 2026 Sensia Software LLC. All Rights Reserved.

******************************* END LICENSE BLOCK ***************************/

package org.sensorhub.impl.service.consys.client;

import com.google.common.base.Strings;
import org.junit.Test;
import org.sensorhub.api.system.IDeploymentWithDesc;
import org.sensorhub.impl.service.consys.resource.ResourceFormat;
import org.sensorhub.impl.service.consys.sensorml.DeploymentAdapter;
import org.vast.sensorML.SMLHelper;

import java.net.HttpURLConnection;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;


public class TestClientDeployments extends TestClientBase
{

public TestClientDeployments() {}

TestClientDeployments(String apiRootUrl) { this.apiRootUrl = apiRootUrl; }


@Test
public void testAddMultipleDeployments() throws Exception {
addDeployment(createDeployment(1), true);
addDeployment(createDeployment(10), true);
}

@Test
public void testAddDeploymentAndGetById() throws Exception {
var deployment = createDeployment(1);
var id = addDeployment(deployment, true);

var result = ConSysApiClient
.newBuilder(apiRootUrl)
.build()
.getDeploymentById(id, ResourceFormat.SML_JSON).get();

assertEquals(id, result.getId());
assertEquals(deployment.getUniqueIdentifier(), result.getUniqueIdentifier());
assertEquals(deployment.getName(), result.getName());
assertEquals(deployment.getDescription(), result.getDescription());
}

@Test
public void testAddDeploymentAndGetByUid() throws Exception {
var deployment = createDeployment(1);
var id = addDeployment(deployment, true);

var r = ConSysApiClient
.newBuilder(apiRootUrl)
.build()
.getDeploymentByUid(deployment.getUniqueIdentifier(), ResourceFormat.SML_JSON).get();

assertEquals(id, r.getId());
assertEquals(deployment.getUniqueIdentifier(), r.getUniqueIdentifier());
assertEquals(deployment.getName(), r.getName());
assertEquals(deployment.getDescription(), r.getDescription());
}


@Test
public void testUpdateDeployment() throws Exception
{
var deployment = createDeployment(2);
var id = addDeployment(deployment, false);

var updated = createDeployment(2);
updated.getFullDescription().setName("Updated deployment name");
updated.getFullDescription().setDescription("Updated deployment description");

var statusCode = ConSysApiClient
.newBuilder(apiRootUrl)
.build()
.updateDeployment(id, updated).get().intValue();

assertEquals(HttpURLConnection.HTTP_NO_CONTENT, statusCode);

var result = ConSysApiClient
.newBuilder(apiRootUrl)
.build()
.getDeploymentById(id, ResourceFormat.SML_JSON).get();

assertEquals(id, result.getId());
assertEquals(updated.getUniqueIdentifier(), result.getUniqueIdentifier());
assertEquals("Updated deployment name", result.getName());
assertEquals("Updated deployment description", result.getDescription());
checkDeploymentIdExists(id);
}


private IDeploymentWithDesc createDeployment(int num)
{
var deploymentUid = getDeploymentUid(num);

var deployment = new SMLHelper().createDeployment()
.uniqueID(deploymentUid)
.name("Test Deployment #" + num)
.description("Test deployment #" + num + " created using Java API client")
.build();
return new DeploymentAdapter(deployment);
}

private String addDeployment(IDeploymentWithDesc deployment, boolean checkHead) throws Exception
{
var id = ConSysApiClient
.newBuilder(apiRootUrl)
.build()
.addDeployment(deployment).get();

assertFalse(Strings.isNullOrEmpty(id));

if (checkHead)
checkDeploymentIdExists(id);

return id;
}

protected String getDeploymentUid(int num)
{
return "urn:osh:test:deployment:" + num;
}


protected void checkDeploymentIdExists(String deploymentId) throws Exception
{
checkUriExists(apiRootUrl + "/" + DEPLOYMENT_COLLECTION + "/" + deploymentId);
}

}
Loading