Skip to content
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

Initial commit - ModelsRepository Client #20033

Merged
merged 9 commits into from
Mar 23, 2021
Merged
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
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
# PRLabel: %Digital Twins
/sdk/digitaltwins/ @drwill-ms @timtay-microsoft @abhipsaMisra @vinagesh @azabbasi @bikamani @barustum

# PRLabel: %Models Repository
/sdk/modelsrepository @drwill-ms @timtay-microsoft @abhipsaMisra @vinagesh @azabbasi @bikamani @barustum @digimaun

# PRLabel: %Event Grid
/sdk/eventgrid/ @srnagar @yijunxiems

Expand Down
1 change: 1 addition & 0 deletions eng/versioning/version_client.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ com.azure:azure-e2e;1.0.0-beta.1;1.0.0-beta.1
com.azure:azure-identity;1.2.4;1.3.0-beta.3
com.azure:azure-identity-perf;1.0.0-beta.1;1.0.0-beta.1
com.azure:azure-iot-deviceupdate;1.0.0-beta.1;1.0.0-beta.2
com.azure:azure-iot-modelsrepository;1.0.0-beta.1;1.0.0-beta.1
com.azure:azure-messaging-eventgrid;4.0.0;4.1.0-beta.1
com.azure:azure-messaging-eventhubs;5.6.0;5.7.0-beta.1
com.azure:azure-messaging-eventhubs-checkpointstore-blob;1.5.1;1.6.0-beta.1
Expand Down
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@
<!-- Mixed Reality -->
<module>sdk/mixedreality/azure-mixedreality-authentication</module>

<!-- Models Repository -->
<module>sdk/modelsrepository/azure-iot-modelsrepository</module>

<!-- Quantum Jobs -->
<module>sdk/quantum/azure-quantum-jobs</module>

Expand Down Expand Up @@ -241,6 +244,10 @@
<title>Azure Digital Twins</title>
<packages>com.azure.digitaltwins.core*</packages>
</group>
<group>
<title>Azure IoT Models Repository</title>
<packages>com.azure.iot.modelsrepository*</packages>
</group>
<group>
<title>Azure Form Recognizer</title>
<packages>com.azure.ai.formrecognizer*</packages>
Expand Down Expand Up @@ -619,6 +626,7 @@
<module>sdk/mediaservices</module>
<module>sdk/metricsadvisor</module>
<module>sdk/mixedreality</module>
<module>sdk/modelsrepository</module>
<module>sdk/monitor</module>
<module>sdk/mysql</module>
<module>sdk/netapp</module>
Expand Down
19 changes: 19 additions & 0 deletions sdk/modelsrepository/azure-iot-modelsrepository/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Release History

## 1.0.0-beta.1 (Unreleased)

### New features

- N/A
azabbasi marked this conversation as resolved.
Show resolved Hide resolved

### Breaking changes

- N/A

### Added

- N/A

### Fixes and improvements

- N/A
36 changes: 36 additions & 0 deletions sdk/modelsrepository/azure-iot-modelsrepository/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Azure IoT Models Repository client library for Java
azabbasi marked this conversation as resolved.
Show resolved Hide resolved

## Getting started

The complete Microsoft Azure SDK can be downloaded from the [Microsoft Azure downloads][microsoft_sdk_download] page, and it ships with support for building deployment packages, integrating with tooling, rich command line tooling, and more.

For the best development experience, developers should use the official Microsoft Maven packages for libraries. Maven packages will be regularly updated with new functionality and hotfixes.

### Include the Package

### Prerequisites

### Authenticate the Client

## Key concepts

## Troubleshooting

## Next steps

## Contributing

This project welcomes contributions and suggestions.
Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution.
For details, visit <https://cla.microsoft.com.>.

When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment).
Simply follow the instructions provided by the bot.
You will only need to do this once across all repos using our CLA.

This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct].
For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

<!-- LINKS -->
[microsoft_sdk_download]: https://azure.microsoft.com/downloads/?sdk=net
[code_of_conduct]: https://opensource.microsoft.com/codeofconduct/
14 changes: 14 additions & 0 deletions sdk/modelsrepository/azure-iot-modelsrepository/build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Builds the azure-iot-modelsrepository project
# The output will be in the target directory.
# You can use the generated azure-iot-modelsrepository-x-sources.jar to upload to the API review tool at https://apiview.dev/

param (
[Parameter(Mandatory = $false)]
[switch] $skipTests
)

if ($skipTests) {
mvn install -DskipTests
} else {
mvn install
}
147 changes: 147 additions & 0 deletions sdk/modelsrepository/azure-iot-modelsrepository/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.azure</groupId>
<artifactId>azure-client-sdk-parent</artifactId>
<version>1.7.0</version> <!-- {x-version-update;com.azure:azure-client-sdk-parent;current} -->
<relativePath>../../parents/azure-client-sdk-parent</relativePath>
</parent>

<groupId>com.azure</groupId>
<artifactId>azure-iot-modelsrepository</artifactId>
<version>1.0.0-beta.1</version> <!-- {x-version-update;com.azure:azure-iot-modelsrepository;current} -->

<name>Microsoft Azure client library for Models Repository</name>
<description>This package contains the Microsoft Azure IoT ModelsRepository client library.</description>
<url>https://github.com/Azure/azure-sdk-for-java</url>

<distributionManagement>
<site>
<id>azure-java-build-docs</id>
<url>${site.url}/site/${project.artifactId}</url>
</site>
</distributionManagement>

<scm>
<url>scm:git:https://github.com/Azure/azure-sdk-for-java</url>
<connection>scm:git:git@github.com:Azure/azure-sdk-for-java.git</connection>
<tag>HEAD</tag>
</scm>

<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core</artifactId>
<version>1.13.0</version> <!-- {x-version-update;com.azure:azure-core;dependency} -->
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-netty</artifactId>
<version>1.8.0</version> <!-- {x-version-update;com.azure:azure-core-http-netty;dependency} -->
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core-test</artifactId>
<version>1.5.3</version> <!-- {x-version-update;com.azure:azure-core-test;dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.2.3</version> <!-- {x-version-update;com.azure:azure-identity;dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-okhttp</artifactId>
<version>1.5.0</version> <!-- {x-version-update;com.azure:azure-core-http-okhttp;dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.3</version> <!-- {x-version-update;org.junit.jupiter:junit-jupiter-api;external_dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.3</version> <!-- {x-version-update;org.junit.jupiter:junit-jupiter-engine;external_dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.6.3</version> <!-- {x-version-update;org.junit.jupiter:junit-jupiter-params;external_dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.16.1</version> <!-- {x-version-update;org.assertj:assertj-core;external_dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.3</version> <!-- {x-version-update;commons-cli:commons-cli;external_dependency} -->
<scope>test</scope>
</dependency>
</dependencies>

<build>
<testResources>
<testResource>
<directory>src/samples/resources</directory>
</testResource>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M3</version> <!-- {x-version-update;org.apache.maven.plugins:maven-enforcer-plugin;external_dependency} -->
<configuration>
<rules>
<bannedDependencies>
<includes>
<include>com.fasterxml.jackson.core:jackson-annotations:[2.12.1]</include> <!-- {x-include-update;com.fasterxml.jackson.core:jackson-annotations;external_dependency} -->
</includes>
</bannedDependencies>
</rules>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>java-lts</id>
<activation>
<jdk>[11,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version> <!-- {x-version-update;org.apache.maven.plugins:maven-surefire-plugin;external_dependency} -->
<configuration>
<argLine>
--add-exports com.azure.core/com.azure.core.implementation.http=ALL-UNNAMED
--add-opens com.azure.iot.modelsrepository/com.azure.iot.modelsrepository=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.iot.modelsrepository;

import com.azure.core.util.UrlBuilder;
import com.azure.iot.modelsrepository.implementation.ModelsRepositoryConstants;
import com.azure.iot.modelsrepository.implementation.StatusStrings;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import java.util.regex.Pattern;

/**
* DtmiConventions implements the core aspects of the IoT model repo conventions
* which includes DTMI validation and calculating a URI path from a DTMI.
*/
public final class DtmiConventions {

private DtmiConventions() { }

/**
* A DTMI has three components: scheme, path, and version.
* Scheme and path are separated by a colon. Path and version are separated by a semicolon i.e. scheme : path ; version.
* The scheme is the string literal "dtmi" in lowercase. The path is a sequence of one or more segments, separated by colons.
* The version is a sequence of one or more digits. Each path segment is a non-empty string containing only letters, digits, and undersc
* The first character may not be a digit, and the last character may not be an underscore.
* The version length is limited to nine digits, because the number 999,999,999 fits in a 32-bit signed integer value.
* The first digit may not be zero, so there is no ambiguity regarding whether version 1 matches version 01 since the latter is invalid.
*/
private static final Pattern VALID_DTMI_PATTERN = Pattern.compile("^dtmi:[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?(?::[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?)*;[1-9][0-9]{0,8}$");

/**
* Indicates whether a given string DTMI value is well-formed.
*
* @param dtmi DigitalTwin Model Id
* @return True if dtmi has a valid format. False otherwise.
*/
public static boolean isValidDtmi(String dtmi) {
if (dtmi == null || dtmi.isEmpty()) {
return false;
}

return VALID_DTMI_PATTERN.matcher(dtmi).matches();
}

/**
* Generates the model URI.
*
* @param dtmi DigitalTwin Model Id.
* @param repositoryUri The repository uri
* @param expanded Is model from precomputed values
* @return The model uri
* Will throw an {@link IllegalArgumentException} if the provided dtmi is not valid.
*/
public static URI getModelUri(String dtmi, URI repositoryUri, boolean expanded) {
String dtmiPath = dtmiToPath(dtmi);

if (expanded) {
dtmiPath = dtmiPath.replace(ModelsRepositoryConstants.JSON_EXTENSION, ModelsRepositoryConstants.JSON_EXPANDED_EXTENSION);
}

UrlBuilder urlBuilder = new UrlBuilder();
urlBuilder.setHost(repositoryUri.getHost());
urlBuilder.setScheme(repositoryUri.getScheme());
urlBuilder.setPath(repositoryUri.getPath());
urlBuilder.setQuery(repositoryUri.getQuery());

if (repositoryUri.getPort() > 0) {
urlBuilder.setPort(repositoryUri.getPort());
}

String path = urlBuilder.getPath();

if (path != null && !path.endsWith("/")) {
urlBuilder.setPath(path + "/");
}

if (urlBuilder.getPath() == null) {
urlBuilder.setPath(dtmiPath);
} else {
urlBuilder.setPath(urlBuilder.getPath() + dtmiPath);
}

try {
return new URI(urlBuilder.toString());
} catch (Exception e) {
// No exceptions will be thrown as the input is a valid URI format.
return null;
}
}

/**
* Converts a string to {@link URI}
*
* @param uri String format of the path
* @return {@link URI} representation of the path/uri .
*/
public static URI convertToUri(String uri) {
try {
return new URI(uri);
} catch (URISyntaxException ex) {
try {
Path path = Paths.get(uri).normalize();
return new File(path.toAbsolutePath().toString()).toURI();
}
catch (Exception e) {
throw new IllegalArgumentException("Invalid uri format", e);
}
}
}

static String dtmiToPath(String dtmi) {
if (!isValidDtmi(dtmi)) {
throw new IllegalArgumentException(String.format(StatusStrings.INVALID_DTMI_FORMAT_S, dtmi));
}

return dtmi
.toLowerCase(Locale.getDefault())
.replaceAll(":", "/")
.replaceAll(";", "-")
+ ModelsRepositoryConstants.JSON_EXTENSION;
}
}
Loading