Skip to content

Commit 158ebde

Browse files
feat: add digital twin manager
1 parent 948261b commit 158ebde

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright (c) 2023. Smart Operating Block
3+
*
4+
* Use of this source code is governed by an MIT-style
5+
* license that can be found in the LICENSE file or at
6+
* https://opensource.org/licenses/MIT.
7+
*/
8+
9+
package infrastructure.digitaltwins;
10+
11+
import com.azure.digitaltwins.core.BasicDigitalTwin;
12+
import com.azure.digitaltwins.core.DigitalTwinsClient;
13+
import com.azure.digitaltwins.core.DigitalTwinsClientBuilder;
14+
import com.azure.digitaltwins.core.implementation.models.ErrorResponseException;
15+
import com.azure.identity.DefaultAzureCredentialBuilder;
16+
import com.google.gson.Gson;
17+
import com.google.gson.JsonObject;
18+
import entity.medicaltechnology.MedicalTechnology;
19+
import entity.medicaltechnology.MedicalTechnologyID;
20+
import entity.room.RoomID;
21+
import infrastructure.digitaltwins.adtpresentation.MedicalTechnologyAdtPresentation;
22+
import jade.util.Logger;
23+
import usecase.repository.MedicalTechnologyRepository;
24+
25+
import java.util.Objects;
26+
import java.util.Optional;
27+
import java.util.function.Function;
28+
29+
/**
30+
* Digital Twin Manager that implements the repositories of the application.
31+
*/
32+
public class DigitalTwinManager implements MedicalTechnologyRepository {
33+
private static final String DT_APP_ID_VARIABLE = "AZURE_CLIENT_ID";
34+
private static final String DT_TENANT_VARIABLE = "AZURE_TENANT_ID";
35+
private static final String DT_APP_SECRET_VARIABLE = "AZURE_CLIENT_SECRET";
36+
private static final String DT_ENDPOINT_VARIABLE = "AZURE_DT_ENDPOINT";
37+
38+
private final DigitalTwinsClient dtClient;
39+
40+
/**
41+
* Default constructor.
42+
*/
43+
public DigitalTwinManager() {
44+
Objects.requireNonNull(System.getenv(DT_APP_ID_VARIABLE), "Azure client app id required");
45+
Objects.requireNonNull(System.getenv(DT_TENANT_VARIABLE), "Azure tenant id required");
46+
Objects.requireNonNull(System.getenv(DT_APP_SECRET_VARIABLE), "Azure client secret id required");
47+
Objects.requireNonNull(System.getenv(DT_ENDPOINT_VARIABLE), "Azure dt endpoint required");
48+
this.dtClient = new DigitalTwinsClientBuilder()
49+
.credential(new DefaultAzureCredentialBuilder().build())
50+
.endpoint(System.getenv(DT_ENDPOINT_VARIABLE))
51+
.buildClient();
52+
}
53+
54+
@Override
55+
public final Optional<MedicalTechnology> findBy(final MedicalTechnologyID medicalTechnologyID) {
56+
return this.applySafeDigitalTwinOperation(Optional.empty(), client -> {
57+
// Get the medical technology digital twin and obtain also the room in which it is located (if present)
58+
return MedicalTechnologyAdtPresentation.toMedicalTechnology(
59+
client.getDigitalTwin(medicalTechnologyID.getId(), BasicDigitalTwin.class)
60+
).map(medicalTechnology -> {
61+
// Get the room if exists
62+
return new MedicalTechnology(medicalTechnology.getId(),
63+
medicalTechnology.getType(),
64+
client.query("SELECT TOP(1) CT.$dtId"
65+
+ "FROM DIGITALTWINS T"
66+
+ "JOIN CT RELATED T."
67+
+ MedicalTechnologyAdtPresentation.IS_LOCATED_IN_OPERATING_ROOM_RELATIONSHIP
68+
+ "WHERE T.$dtId = '"
69+
+ medicalTechnologyID.getId()
70+
+ "'",
71+
String.class).stream()
72+
.findFirst()
73+
.map(firstResult ->
74+
new RoomID(new Gson().fromJson(firstResult, JsonObject.class).get("$dtId").getAsString())
75+
)
76+
);
77+
});
78+
});
79+
}
80+
81+
private <R> R applySafeDigitalTwinOperation(final R defaultResult, final Function<DigitalTwinsClient, R> operation) {
82+
try {
83+
return operation.apply(this.dtClient);
84+
} catch (final ErrorResponseException exception) {
85+
Logger.getLogger(DigitalTwinManager.class.toString()).fine(exception.getMessage());
86+
return defaultResult;
87+
}
88+
}
89+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2023. Smart Operating Block
3+
*
4+
* Use of this source code is governed by an MIT-style
5+
* license that can be found in the LICENSE file or at
6+
* https://opensource.org/licenses/MIT.
7+
*/
8+
9+
package infrastructure.digitaltwins.adtpresentation;
10+
11+
import com.azure.digitaltwins.core.BasicDigitalTwin;
12+
import entity.medicaltechnology.MedicalTechnology;
13+
import entity.medicaltechnology.MedicalTechnologyID;
14+
import entity.medicaltechnology.MedicalTechnologyType;
15+
16+
import java.util.Optional;
17+
18+
/**
19+
* Presentation-related stuff for Azure Digital Twins about medical technologies.
20+
*/
21+
public final class MedicalTechnologyAdtPresentation {
22+
/** Relationship from room to medical technology. */
23+
public static final String IS_LOCATED_IN_OPERATING_ROOM_RELATIONSHIP = "rel_is_located";
24+
25+
private static final String TYPE_PROPERTY = "type";
26+
private static final String TYPE_ENDOSCOPE = "0";
27+
private static final String TYPE_XRAY = "1";
28+
29+
private MedicalTechnologyAdtPresentation() { }
30+
31+
/**
32+
* Convert a {@link BasicDigitalTwin} to a {@link MedicalTechnology}.
33+
* @param digitalTwin the digital twin to convert
34+
* @return an optional with the medical technology if the conversion is possible, an empty optional otherwise
35+
*/
36+
public static Optional<MedicalTechnology> toMedicalTechnology(final BasicDigitalTwin digitalTwin) {
37+
if (digitalTwin.getContents().containsKey(TYPE_PROPERTY)) {
38+
final Optional<MedicalTechnologyType> medicalTechnologyType =
39+
toMedicalTechnologyType((String) digitalTwin.getContents().get(TYPE_PROPERTY));
40+
return medicalTechnologyType.map(type -> new MedicalTechnology(new MedicalTechnologyID(digitalTwin.getId()), type));
41+
}
42+
return Optional.empty();
43+
}
44+
45+
private static Optional<MedicalTechnologyType> toMedicalTechnologyType(final String medicalTechnologyType) {
46+
return switch (medicalTechnologyType) {
47+
case TYPE_ENDOSCOPE -> Optional.of(MedicalTechnologyType.ENDOSCOPE);
48+
case TYPE_XRAY -> Optional.of(MedicalTechnologyType.XRAY);
49+
default -> Optional.empty();
50+
};
51+
}
52+
}

0 commit comments

Comments
 (0)