-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add helpers for accessing sample resources #14706
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: Add a command line options helper similar to .NET There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add the "TODO:" as a comment so we can find it and resolve it later? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will take care of this |
||
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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This path to "resources" is returned as a URL |
||
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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ModelPath and RelationshipsPath is not used here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will be, in the rest of the sample (this sample creates models and relationships) :) |
||
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" | ||
} | ||
] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maven has inbuilt references to src/main/resources and src/test/resources. We need to add reference to src/samples/resources explicitly.