Skip to content

Commit

Permalink
Adds feature to get all submodels from a shell (eclipse-basyx#293)
Browse files Browse the repository at this point in the history
* Adds feature to get all submodels from a shell

Signed-off-by: Jannis Jung <[email protected]>

* Applies Formatter

Signed-off-by: Jannis Jung <[email protected]>

* Fixes Java Doc

Signed-off-by: Jannis Jung <[email protected]>

* Fix minor issues

---------

Signed-off-by: Jannis Jung <[email protected]>
Co-authored-by: Mateus Molina <[email protected]>
  • Loading branch information
jannisjung and mateusmolina-iese authored May 28, 2024
1 parent 17f58ad commit 7497777
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,15 @@

package org.eclipse.digitaltwin.basyx.aasenvironment.client;

import java.util.List;
import java.util.stream.Collectors;

import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.util.AasUtils;
import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
import org.eclipse.digitaltwin.aas4j.v3.model.Key;
import org.eclipse.digitaltwin.aas4j.v3.model.KeyTypes;
import org.eclipse.digitaltwin.aas4j.v3.model.Reference;
import org.eclipse.digitaltwin.aas4j.v3.model.ReferenceTypes;
import org.eclipse.digitaltwin.aas4j.v3.model.Submodel;
import org.eclipse.digitaltwin.basyx.aasenvironment.client.exceptions.NoValidEndpointFoundException;
import org.eclipse.digitaltwin.basyx.aasenvironment.client.exceptions.RegistryHttpRequestException;
Expand All @@ -46,7 +53,7 @@
/**
* Client component for executing consolidated Repository and Registry requests
*
* @author mateusmolina
* @author mateusmolina, jungjan
*
*/
public class ConnectedAasManager {
Expand Down Expand Up @@ -126,6 +133,22 @@ public ConnectedSubmodelService getSubmodel(String identifier) {
return smDescriptorResolver.resolveSubmodelDescriptor(descriptor);
}

/**
* Retrieves all registered Submodels of a registered Asset Administration Shell
*
* @param shellIdentifier
* The identifier of the Shell to retrieve.
* @return The retrieved Submodel object.
*/
public List<ConnectedSubmodelService> getAllSubmodels(String shellIdentifier) {
AssetAdministrationShell shell = getAas(shellIdentifier).getAAS();
List<Reference> submodelReferences = shell.getSubmodels();
return submodelReferences.parallelStream()
.map(this::extractSubmodelIdentifierFromReference)
.map(this::getSubmodel)
.collect(Collectors.toList());
}

/**
* Deletes an AAS by its identifier.
*
Expand Down Expand Up @@ -199,5 +222,30 @@ public void createSubmodelInAas(String aasIdentifier, Submodel submodel) {
aasRepository.addSubmodelReference(aasIdentifier, AasUtils.toReference(submodel));
}

}
private String extractSubmodelIdentifierFromReference(Reference submodelReference) {
assertIsSubmodelReference(submodelReference);
Key submodelKey = extractSubmodelKeyFromReference(submodelReference);
return submodelKey.getValue();
}

private void assertIsSubmodelReference(Reference submodelReference) {
if (!submodelReference.getType()
.equals(ReferenceTypes.MODEL_REFERENCE)) {
throw new RuntimeException("A submodel reference must be of type MODEL_REFERENCE.");
}
assertFirstKeyIsOfTypeSubmodel(submodelReference);
}

private void assertFirstKeyIsOfTypeSubmodel(Reference submodelReference) {
if (!extractSubmodelKeyFromReference(submodelReference).getType()
.equals(KeyTypes.SUBMODEL)) {
throw new RuntimeException("The first key of a submodelReference must be of KeyType SUBMODEL submodel..");
}
}

private Key extractSubmodelKeyFromReference(Reference submodelReference) {
return submodelReference.getKeys()
.get(0);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@
*/
@SuppressWarnings("serial")
public class NoValidEndpointFoundException extends RuntimeException {
/**
* Constructs a NoValidEndpointException
*
* @param endpoints
*/
public NoValidEndpointFoundException(String endpoints) {
super(getMessage(endpoints));
}

public static String getMessage(String endpoints) {
private static String getMessage(String endpoints) {
return "No valid endpoint found in " + endpoints;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@
@SuppressWarnings("serial")
public class RegistryHttpRequestException extends RuntimeException {

/**
* Constructs a RegistryHttpRequestExcrption
*
* @param id
* The Identifier of the Identifiable
* @param th
* The original exception
*/
public RegistryHttpRequestException(String id, Throwable th) {
super(getMessage(id), th);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,21 @@ public class AasDescriptorResolver {

private final EndpointResolver endpointResolver;

/**
* Creates an AASDescriptorResolver
*
* @param endpointResolver
*/
public AasDescriptorResolver(EndpointResolver endpointResolver) {
this.endpointResolver = endpointResolver;
}

/**
* Resolves an AASDescriptor to a ConnectedAasService
*
* @param aasDescriptor
* @return
*/
public ConnectedAasService resolveAasDescriptor(AssetAdministrationShellDescriptor aasDescriptor) {
String endpoint = endpointResolver.resolveFirst(aasDescriptor.getEndpoints(), AasDescriptorResolver::parseEndpoint);

Expand All @@ -54,10 +65,12 @@ public ConnectedAasService resolveAasDescriptor(AssetAdministrationShellDescript

private static Optional<URI> parseEndpoint(Endpoint endpoint) {
try {
if (endpoint == null || endpoint.getProtocolInformation() == null || endpoint.getProtocolInformation().getHref() == null)
if (endpoint == null || endpoint.getProtocolInformation() == null || endpoint.getProtocolInformation()
.getHref() == null)
return Optional.empty();

String baseHref = endpoint.getProtocolInformation().getHref();
String baseHref = endpoint.getProtocolInformation()
.getHref();
// TODO not working: String queryString = "?" + endpoint.toUrlQueryString();
String queryString = "";
URI uri = new URI(baseHref + queryString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,33 +39,69 @@
*
*/
public class EndpointResolver {

private int timeout = 3000;

/**
* Creates an EndpointResolver with default timeout
*/
public EndpointResolver() {
}

/**
* Creates an EndpointResolver with a custom timeout
*
* @param timeout
*/
public EndpointResolver(int timeout) {
this.timeout = timeout;
}

/**
* Resolves the first working Endpoint from a list of endpoints
*
* @param <T>
* @param endpoints
* @param uriParser
* @return
*/
public <T> String resolveFirst(List<T> endpoints, URIParser<T> uriParser) {
List<URI> uris = endpoints.stream().map(uriParser::parse).flatMap(Optional::stream).toList();
return findFirstWorkingURI(uris).orElseThrow(() -> new NoValidEndpointFoundException(endpoints.toString())).toString();
List<URI> uris = endpoints.stream()
.map(uriParser::parse)
.flatMap(Optional::stream)
.toList();
return findFirstWorkingURI(uris).orElseThrow(() -> new NoValidEndpointFoundException(endpoints.toString()))
.toString();
}

/**
* Resolves all working endpoints from a list of endpoints
*
* @param <T>
* @param endpoints
* @param uriParser
* @return
*/
public <T> List<String> resolveAll(List<T> endpoints, URIParser<T> uriParser) {
return endpoints.stream().map(uriParser::parse).flatMap(Optional::stream).filter(this::isURIWorking).map(URI::toString).toList();
return endpoints.stream()
.map(uriParser::parse)
.flatMap(Optional::stream)
.filter(this::isURIWorking)
.map(URI::toString)
.toList();
}

private Optional<URI> findFirstWorkingURI(List<URI> uris) {
return uris.stream().filter(this::isURIWorking).findFirst();
return uris.stream()
.filter(this::isURIWorking)
.findFirst();
}

private boolean isURIWorking(URI uri) {
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) uri.toURL().openConnection();
connection = (HttpURLConnection) uri.toURL()
.openConnection();
connection.setRequestMethod("HEAD");
connection.setConnectTimeout(timeout);
connection.setReadTimeout(timeout);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import org.eclipse.digitaltwin.basyx.submodelservice.client.ConnectedSubmodelService;

/**
* Resolves an SubmodelDescriptor into a Submodel
* Resolves a SubmodelDescriptor into a Submodel
*
* @author mateusmolina
*
Expand All @@ -42,10 +42,22 @@ public class SubmodelDescriptorResolver {

private final EndpointResolver endpointResolver;

/**
* Constructs a SubmodelDescriptorResolver
*
* @param endpointResolver
*/
public SubmodelDescriptorResolver(EndpointResolver endpointResolver) {
this.endpointResolver = endpointResolver;
}

/**
* Resolves a Submodel Descriptor to a Connected SubmodelService
*
* @param smDescriptor
* the Submodel Descriptor to be resolved
* @return the Connected submodelserver
*/
public ConnectedSubmodelService resolveSubmodelDescriptor(SubmodelDescriptor smDescriptor) {
String endpoint = endpointResolver.resolveFirst(smDescriptor.getEndpoints(), SubmodelDescriptorResolver::parseEndpoint);

Expand All @@ -54,10 +66,12 @@ public ConnectedSubmodelService resolveSubmodelDescriptor(SubmodelDescriptor smD

private static Optional<URI> parseEndpoint(Endpoint endpoint) {
try {
if (endpoint == null || endpoint.getProtocolInformation() == null || endpoint.getProtocolInformation().getHref() == null)
if (endpoint == null || endpoint.getProtocolInformation() == null || endpoint.getProtocolInformation()
.getHref() == null)
return Optional.empty();

String baseHref = endpoint.getProtocolInformation().getHref();
String baseHref = endpoint.getProtocolInformation()
.getHref();
// TODO not working: String queryString = "?" + endpoint.toUrlQueryString();
String queryString = "";
URI uri = new URI(baseHref + queryString);
Expand Down
Loading

0 comments on commit 7497777

Please sign in to comment.