Skip to content

Commit

Permalink
Refactors AASEnvironment and implements auth for upload endpoint (ecl…
Browse files Browse the repository at this point in the history
…ipse-basyx#232)

* Fixes upload endpoint not working with auth

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

* test

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

* Refactors AASEnvironment and implements auth for upload endpoint

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

* Updates the rbac_rules

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

* Refactors code

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

* Minor refactoring

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

* Refactors variable names

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

---------

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>
  • Loading branch information
mdanish98 authored Mar 1, 2024
1 parent 1c26c01 commit 1baf5a8
Show file tree
Hide file tree
Showing 27 changed files with 801 additions and 350 deletions.
4 changes: 3 additions & 1 deletion basyx.aasenvironment/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ Furthermore, if Identifiables (AAS, Submodels, ConceptDescriptions) are already

For examples, see [application.properties](./basyx.aasenvironment.component/src/main/resources/application.properties)


## AAS Environment Upload Endpoint

AAS environments (e.g. XML, JSON, AASX) can be uploaded to the `/upload` endpoint.

The upload follows the same rules as the preconfiguration in terms of handling existing AAS, submodels and concept descriptions. In order for the file to be recognized correctly, please make sure that its MIME type is properly configured.

## AAS Environment Features
* [AAS Environment Authorization](basyx.aasenvironment-feature-authorization)
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.List;

import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.SerializationException;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.CompleteEnvironment;

/**
* Specifies the overall AasEnvironment API
Expand All @@ -51,4 +52,6 @@ public interface AasEnvironment {
public String createXMLAASEnvironmentSerialization(List<String> aasIds, List<String> submodelIds, boolean includeConceptDescriptions) throws SerializationException;

public byte[] createAASXAASEnvironmentSerialization(List<String> aasIds, List<String> submodelIds, boolean includeConceptDescriptions) throws SerializationException, IOException;

public void loadEnvironment(CompleteEnvironment completeEnvironment);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,38 @@
******************************************************************************/
package org.eclipse.digitaltwin.basyx.aasenvironment.base;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.io.FilenameUtils;
import org.eclipse.digitaltwin.aas4j.v3.dataformat.aasx.AASXSerializer;
import org.eclipse.digitaltwin.aas4j.v3.dataformat.aasx.InMemoryFile;
import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.SerializationException;
import org.eclipse.digitaltwin.aas4j.v3.dataformat.json.JsonSerializer;
import org.eclipse.digitaltwin.aas4j.v3.dataformat.xml.XmlSerializer;
import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
import org.eclipse.digitaltwin.aas4j.v3.model.ConceptDescription;
import org.eclipse.digitaltwin.aas4j.v3.model.Environment;
import org.eclipse.digitaltwin.aas4j.v3.model.Submodel;
import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement;
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.AasEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.ConceptDescriptionIdCollector;
import org.eclipse.digitaltwin.basyx.aasenvironment.FileElementPathCollector;
import org.eclipse.digitaltwin.basyx.aasenvironment.IdShortPathBuilder;
import org.eclipse.digitaltwin.basyx.aasenvironment.MetamodelCloneCreator;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.CompleteEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.IdentifiableUploader;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.IdentifiableAssertion;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.IdentifiableUploader.DelegatingIdentifiableRepository;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.IdentifiableUploader.IdentifiableRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.ConceptDescriptionRepository;
import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException;
Expand All @@ -68,6 +81,7 @@ public class DefaultAASEnvironment implements AasEnvironment {
private XmlSerializer xmlSerializer = new XmlSerializer();
private AASXSerializer aasxSerializer = new AASXSerializer();
private MetamodelCloneCreator cloneCreator = new MetamodelCloneCreator();
private IdentifiableAssertion checker = new IdentifiableAssertion();

public DefaultAASEnvironment(AasRepository aasRepository, SubmodelRepository submodelRepository, ConceptDescriptionRepository conceptDescriptionRepository) {
this.aasRepository = aasRepository;
Expand Down Expand Up @@ -96,6 +110,108 @@ public byte[] createAASXAASEnvironmentSerialization(@Valid List<String> aasIds,
aasxSerializer.write(aasEnvironment, null, outputStream);
return outputStream.toByteArray();
}

public void loadEnvironment(CompleteEnvironment completeEnvironment) {
Environment environment = completeEnvironment.getEnvironment();

if (environment == null)
return;

checker.assertNoDuplicateIds(environment);

createShellsOnRepositoryFromEnvironment(environment);
createSubmodelsOnRepositoryFromEnvironment(environment, completeEnvironment.getRelatedFiles());
createConceptDescriptionsOnRepositoryFromEnvironment(environment);
}

private void createConceptDescriptionsOnRepositoryFromEnvironment(Environment environment) {
IdentifiableRepository<ConceptDescription> repo = new DelegatingIdentifiableRepository<ConceptDescription>(conceptDescriptionRepository::getConceptDescription, conceptDescriptionRepository::updateConceptDescription,
conceptDescriptionRepository::createConceptDescription);
IdentifiableUploader<ConceptDescription> uploader = new IdentifiableUploader<ConceptDescription>(repo);
for (ConceptDescription conceptDescription : environment.getConceptDescriptions()) {
boolean success = uploader.upload(conceptDescription);
logSuccessConceptDescription(conceptDescription.getId(), success);
}
}

private void createSubmodelsOnRepositoryFromEnvironment(Environment environment, List<InMemoryFile> relatedFiles) {
List<Submodel> submodels = environment.getSubmodels();

createSubmodelsOnRepository(submodels);

if (relatedFiles == null || relatedFiles.isEmpty())
return;

for (Submodel submodel : submodels) {
List<List<SubmodelElement>> idShortElementPathsOfAllFileSMEs = new FileElementPathCollector(submodel).collect();

idShortElementPathsOfAllFileSMEs.stream().forEach(fileSMEIdShortPath -> setFileToFileElement(submodel.getId(), fileSMEIdShortPath, relatedFiles));
}
}

private void setFileToFileElement(String submodelId, List<SubmodelElement> fileSMEIdShortPathElements, List<InMemoryFile> relatedFiles) {
String fileSMEIdShortPath = new IdShortPathBuilder(new ArrayList<>(fileSMEIdShortPathElements)).build();

org.eclipse.digitaltwin.aas4j.v3.model.File fileSME = (org.eclipse.digitaltwin.aas4j.v3.model.File) submodelRepository.getSubmodelElement(submodelId, fileSMEIdShortPath);

InMemoryFile inMemoryFile = getAssociatedInMemoryFile(relatedFiles, fileSME.getValue());

if (inMemoryFile == null) {
logger.info("Unable to set file to the SubmodelElement File with IdShortPath '{}' because it does not exist in the AASX file.", fileSMEIdShortPath);

return;
}

submodelRepository.setFileValue(submodelId, fileSMEIdShortPath, getFileName(inMemoryFile.getPath()), new ByteArrayInputStream(inMemoryFile.getFileContent()));
}

private String getFileName(String path) {
return FilenameUtils.getName(path);
}

private InMemoryFile getAssociatedInMemoryFile(List<InMemoryFile> relatedFiles, String value) {

Optional<InMemoryFile> inMemoryFile = relatedFiles.stream().filter(file -> file.getPath().equals(value)).findAny();

if (inMemoryFile.isEmpty())
return null;

return inMemoryFile.get();
}

private void createShellsOnRepositoryFromEnvironment(Environment environment) {
IdentifiableRepository<AssetAdministrationShell> repo = new DelegatingIdentifiableRepository<AssetAdministrationShell>(aasRepository::getAas, aasRepository::updateAas, aasRepository::createAas);
IdentifiableUploader<AssetAdministrationShell> uploader = new IdentifiableUploader<>(repo);
for (AssetAdministrationShell shell : environment.getAssetAdministrationShells()) {
boolean success = uploader.upload(shell);
logSuccess("shell", shell.getId(), success);
}
}

private void createSubmodelsOnRepository(List<Submodel> submodels) {
IdentifiableRepository<Submodel> repo = new DelegatingIdentifiableRepository<Submodel>(submodelRepository::getSubmodel, submodelRepository::updateSubmodel, submodelRepository::createSubmodel);
IdentifiableUploader<Submodel> uploader = new IdentifiableUploader<>(repo);
for (Submodel submodel : submodels) {
boolean success = uploader.upload(submodel);
logSuccess("submodel", submodel.getId(), success);
}
}

private void logSuccess(String resourceName, String id, boolean success) {
if (success) {
logger.info("Uploading " + resourceName + " " + id + " was successful!");
} else {
logger.warn("Uploading " + resourceName + " " + id + " was not successful!");
}
}

private void logSuccessConceptDescription(String conceptDescriptionId, boolean success) {
if (!success) {
logger.warn("Colliding Ids detected for ConceptDescription: " + conceptDescriptionId + ". If they are not identical, this is an error. Please note that the already existing ConceptDescription was not updated.");
} else {
logSuccess("conceptDescription", conceptDescriptionId, success);
}
}

private Environment createEnvironment(List<String> aasIds, List<String> submodelIds, boolean includeConceptDescriptions) {
List<AssetAdministrationShell> shells = aasIds.stream().map(aasRepository::getAas).collect(Collectors.toList());
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
* @author Gerhard Sonnenberg DFKI GmbH
*
*/
public class IndentifiableAssertion {
public class IdentifiableAssertion {

private final Set<String> currentShellIds = new HashSet<>();
private final Set<String> currentSubmodelIds = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.DeserializationException;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.AasEnvironmentLoader;
import org.eclipse.digitaltwin.basyx.aasenvironment.AasEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.CompleteEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.CompleteEnvironment.EnvironmentType;
import org.slf4j.Logger;
Expand Down Expand Up @@ -70,7 +70,7 @@ public boolean shouldLoadPreconfiguredEnvironment() {
return pathsToLoad != null;
}

public void loadPreconfiguredEnvironments(AasEnvironmentLoader environmentLoader)
public void loadPreconfiguredEnvironments(AasEnvironment aasEnvironment)
throws IOException, DeserializationException, InvalidFormatException {
List<File> files = scanForEnvironments(pathsToLoad);

Expand All @@ -82,7 +82,7 @@ public void loadPreconfiguredEnvironments(AasEnvironmentLoader environmentLoader

for (File file : files) {
logLoadingProcess(currenFileIndex++, filesCount, file.getName());
environmentLoader.loadEnvironment(CompleteEnvironment.fromFile(file));
aasEnvironment.loadEnvironment(CompleteEnvironment.fromFile(file));
}
}

Expand Down
Loading

0 comments on commit 1baf5a8

Please sign in to comment.