Skip to content

Commit

Permalink
Add helpers for accessing sample resources (#14706)
Browse files Browse the repository at this point in the history
* feat(adt): Add helpers for accessing sample's resources
  • Loading branch information
abhipsaMisra authored Sep 2, 2020
1 parent 087377f commit 73a8ec3
Show file tree
Hide file tree
Showing 15 changed files with 383 additions and 0 deletions.
5 changes: 5 additions & 0 deletions sdk/digitaltwins/azure-digitaltwins-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@
</dependencies>

<build>
<resources>
<resource>
<directory>src/samples/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.digitaltwins.core;

import com.azure.core.http.policy.HttpLogDetailLevel;
import com.azure.core.http.policy.HttpLogOptions;
import com.azure.digitaltwins.core.implementation.models.ErrorResponseException;
import com.azure.identity.ClientSecretCredentialBuilder;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class DigitalTwinsLifecycleSample {
private static final String tenantId = System.getenv("TENANT_ID");
private static final String clientId = System.getenv("CLIENT_ID");
private static final String clientSecret = System.getenv("CLIENT_SECRET");
private static final String endpoint = System.getenv("DIGITAL_TWINS_ENDPOINT");

private static final int MaxWaitTimeAsyncOperationsInSeconds = 10;

private static final URL DtdlDirectoryUrl = DigitalTwinsLifecycleSample.class.getClassLoader().getResource("DTDL");
private static final Path DtDlDirectoryPath;
private static final Path TwinsPath;
private static final Path ModelsPath;
private static final Path RelationshipsPath;

private static final DigitalTwinsAsyncClient client;

static {
try {
assert DtdlDirectoryUrl != null;
DtDlDirectoryPath = Paths.get(DtdlDirectoryUrl.toURI());
} catch (URISyntaxException e) {
System.err.println("Unable to convert the DTDL directory URL to URI: " + e);
throw new RuntimeException(e);
}
TwinsPath = Paths.get(DtDlDirectoryPath.toString(), "DigitalTwins");
ModelsPath = Paths.get(DtDlDirectoryPath.toString(), "Models");
RelationshipsPath = Paths.get(DtDlDirectoryPath.toString(), "Relationships");

client = new DigitalTwinsClientBuilder()
.tokenCredential(
new ClientSecretCredentialBuilder()
.tenantId(tenantId)
.clientId(clientId)
.clientSecret(clientSecret)
.build()
)
.endpoint(endpoint)
.httpLogOptions(
new HttpLogOptions()
.setLogLevel(HttpLogDetailLevel.NONE))
.buildAsyncClient();
}

public static void main(String[] args) throws IOException, InterruptedException {
// Ensure existing twins with the same name are deleted first
deleteTwins();

// Create twin counterparts for all the models
createTwins();
}

public static void deleteTwins() throws IOException, InterruptedException {
System.out.println("DELETE DIGITAL TWINS");
Map<String, String> twins = FileHelper.loadAllFilesInPath(TwinsPath);
final Semaphore deleteTwinsSemaphore = new Semaphore(0);

// Call APIs to delete the twins. For each async operation, once the operation is completed successfully, a semaphore is released.
twins
.forEach((twinId, twinContent) -> client.deleteDigitalTwin(twinId)
.doOnSuccess(aVoid -> System.out.println("Deleted digital twin: " + twinId))
.doOnError(throwable -> {
// If digital twin does not exist, ignore.
if (!(throwable instanceof ErrorResponseException) || !((ErrorResponseException) throwable).getValue().getError().getCode().equals("DigitalTwinNotFound")) {
System.err.println("Could not delete digital twin " + twinId + " due to " + throwable);
}
})
.doOnTerminate(deleteTwinsSemaphore::release)
.subscribe());

// Verify that a semaphore has been released for each async operation, signifying that the async call has completed.
boolean created = deleteTwinsSemaphore.tryAcquire(twins.size(), MaxWaitTimeAsyncOperationsInSeconds, TimeUnit.SECONDS);
System.out.println("Twins deleted: " + created);
}

public static void createTwins() throws IOException, InterruptedException {
System.out.println("CREATE DIGITAL TWINS");
Map<String, String> twins = FileHelper.loadAllFilesInPath(TwinsPath);
final Semaphore createTwinsSemaphore = new Semaphore(0);

// Call APIs to create the twins. For each async operation, once the operation is completed successfully, a semaphore is released.
twins
.forEach((twinId, twinContent) -> client.createDigitalTwinWithResponse(twinId, twinContent)
.doOnSuccess(response -> System.out.println("Created digital twin: " + twinId + "\n\t Body: " + response.getValue()))
.doOnError(throwable -> System.err.println("Could not create digital twin " + twinId + " due to " + throwable))
.doOnTerminate(createTwinsSemaphore::release)
.subscribe());

// Verify that a semaphore has been released for each async operation, signifying that the async call has completed.
boolean created = createTwinsSemaphore.tryAcquire(twins.size(), MaxWaitTimeAsyncOperationsInSeconds, TimeUnit.SECONDS);
System.out.println("Twins created: " + created);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.digitaltwins.core;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class FileHelper {
public static Map<String, String> loadAllFilesInPath(Path path) throws IOException {
Map<String, String> fileContents = new HashMap<>();

Stream<Path> paths = Files.walk(path);
paths
.filter(filePath -> filePath.toFile().getName().endsWith(".json"))
.forEach(filePath -> {
try {
Stream<String> lines = Files.lines(filePath);
String fileAsString = lines.collect(Collectors.joining());
lines.close();

fileContents.put(getFileNameFromPath(filePath), cleanupJsonString(fileAsString));
} catch (IOException e) {
e.printStackTrace();
}
});

return fileContents;
}

public static String cleanupJsonString(String jsonString) {
// Remove newline characters, empty spaces and unwanted unicode characters
return jsonString.replaceAll("([\\r\\n\\s+\\uFEFF-\\uFFFF])", "");
}

public static String getFileNameFromPath(Path path) {
String fileName = path.getFileName().toString();
if (fileName.indexOf(".") > 0) {
fileName = fileName.substring(0, fileName.lastIndexOf("."));
}

return fileName;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.digitaltwins.core;

public class SamplesConstants {
public static final String RoomModelId = "dtmi:samples:Room;1";
public static final String WifiModelId = "dtmi:samples:Wifi;1";
public static final String BuildingModelId = "dtmi:samples:Building;1";
public static final String FloorModelId = "dtmi:samples:Floor;1";
public static final String HvacModelId = "dtmi:samples:HVAC;1";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$metadata": {
"$model": "dtmi:samples:Building;1"
},
"AverageTemperature": 68,
"TemperatureUnit": "Celsius"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$metadata": {
"$model": "dtmi:samples:Building;1"
},
"AverageTemperature": 68,
"TemperatureUnit": "Celsius"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$metadata": {
"$model": "dtmi:samples:Floor;1"
},
"AverageTemperature": 75
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$metadata": {
"$model": "dtmi:samples:HVAC;1"
},
"Efficiency": 94,
"TargetTemperature": 72,
"TargetHumidity": 30
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$metadata": {
"$model": "dtmi:samples:Room;1"
},
"Temperature": 80,
"Humidity": 25,
"IsOccupied": true,
"EmployeeId": "Employee1",
"wifiAccessPoint": {
"$metadata": {
},
"RouterName": "Cisco1",
"Network": "Room1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"@id": "dtmi:samples:Building;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;2",
"displayName": "Building",
"contents": [
{
"@type": "Relationship",
"name": "has",
"target": "dtmi:samples:Floor;1",
"properties": [
{
"@type": "Property",
"name": "isAccessRestricted",
"schema": "boolean"
}
]
},
{
"@type": "Relationship",
"name": "isEquippedWith",
"target": "dtmi:samples:HVAC;1"
},
{
"@type": "Property",
"name": "AverageTemperature",
"schema": "double"
},
{
"@type": "Property",
"name": "TemperatureUnit",
"schema": "string"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"@id": "dtmi:samples:Floor;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;2",
"displayName": "Floor",
"contents": [
{
"@type": "Relationship",
"name": "contains",
"target": "dtmi:samples:Room;1"
},
{
"@type": "Property",
"name": "AverageTemperature",
"schema": "double"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"@id": "dtmi:samples:HVAC;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;2",
"displayName": "HVAC",
"contents": [
{
"@type": "Property",
"name": "Efficiency",
"schema": "double"
},
{
"@type": "Property",
"name": "TargetTemperature",
"schema": "double"
},
{
"@type": "Property",
"name": "TargetHumidity",
"schema": "double"
},
{
"@type": "Relationship",
"name": "controlsTemperature",
"target": "dtmi:samples:Floor;1"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"@id": "dtmi:samples:Room;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;2",
"displayName": "Room",
"contents": [
{
"@type": "Property",
"name": "Temperature",
"schema": "double"
},
{
"@type": "Property",
"name": "Humidity",
"schema": "double"
},
{
"@type": "Property",
"name": "IsOccupied",
"schema": "boolean"
},
{
"@type": "Property",
"name": "EmployeeId",
"schema": "string"
},
{
"@type": "Component",
"name": "wifiAccessPoint",
"schema": "dtmi:samples:Wifi;1"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"@id": "dtmi:samples:Wifi;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;2",
"displayName": "Wifi",
"contents": [
{
"@type": "Property",
"name": "RouterName",
"schema": "string"
},
{
"@type": "Property",
"name": "Network",
"schema": "string"
}
]
}
Loading

0 comments on commit 73a8ec3

Please sign in to comment.