diff --git a/.github/workflows/maven-publish-snapshot.yml b/.github/workflows/maven-publish-snapshot.yml
index 77e4f548..ded98ec9 100644
--- a/.github/workflows/maven-publish-snapshot.yml
+++ b/.github/workflows/maven-publish-snapshot.yml
@@ -37,7 +37,7 @@ jobs:
packages: write
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
diff --git a/.github/workflows/maven-run-tests.yml b/.github/workflows/maven-run-tests.yml
index b297cda0..19f93c8d 100644
--- a/.github/workflows/maven-run-tests.yml
+++ b/.github/workflows/maven-run-tests.yml
@@ -49,7 +49,7 @@ jobs:
- 27017:27017
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
diff --git a/.gitignore b/.gitignore
index 42416d97..aef5e14f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,9 @@
.lck
*.class
+/basyx.components/basyx.components.docker/basyx.components.AASServer/fileSmeIdShort.xml
+/basyx.components/basyx.components.docker/basyx.components.AASServer/mySubmodelId-fileSmeIdShort.xml
+/basyx.components/basyx.components.docker/basyx.components.registry/.moquette_uuid
+
/components/basys.components/WebContent/WEB-INF/lib/jdbc/postgresql-42.2.2.jar
/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/aopalliance-repackaged-2.5.0-b42.jar
/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/cdi-api-1.1.jar
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/pom.xml b/basyx.components/basyx.components.docker/basyx.components.AASServer/pom.xml
index 36777c42..5d457d3a 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/pom.xml
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/pom.xml
@@ -7,7 +7,7 @@
org.eclipse.basyx
basyx.components.docker
- 1.4.0
+ 1.5.0
basyx.components.AASServer
@@ -80,14 +80,14 @@
org.mongodb
mongodb-driver-sync
- 4.9.0
+ 4.10.2
org.springframework.data
spring-data-mongodb
- 3.4.10
+ 3.4.15
@@ -108,7 +108,7 @@
io.moquette
moquette-broker
- 0.16
+ 0.17
test
@@ -121,14 +121,14 @@
org.eclipse.basyx
basyx.components.registry
- 1.4.0
+ 1.5.0
test
com.tngtech.keycloakmock
mock
test
- 0.13.0
+ 0.15.2
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/AASServerComponent.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/AASServerComponent.java
index 9ef7a4c7..7c8d78c4 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/AASServerComponent.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/AASServerComponent.java
@@ -24,20 +24,24 @@
******************************************************************************/
package org.eclipse.basyx.components.aas;
+import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.servlet.http.HttpServlet;
import javax.xml.parsers.ParserConfigurationException;
+import org.apache.catalina.Context;
+import org.apache.catalina.core.StandardContext;
import org.apache.catalina.servlets.DefaultServlet;
+import org.apache.catalina.startup.Tomcat;
import org.apache.commons.io.IOUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.eclipse.basyx.aas.aggregator.AASAggregatorAPIHelper;
@@ -61,7 +65,6 @@
import org.eclipse.basyx.components.aas.aascomponent.IAASServerFeature;
import org.eclipse.basyx.components.aas.aascomponent.InMemoryAASServerComponentFactory;
import org.eclipse.basyx.components.aas.aascomponent.MongoDBAASServerComponentFactory;
-import org.eclipse.basyx.components.aas.aasx.AASXPackageManager;
import org.eclipse.basyx.components.aas.authorization.AuthorizedAASServerFeature;
import org.eclipse.basyx.components.aas.authorization.internal.AuthorizedAASServerFeatureFactory;
import org.eclipse.basyx.components.aas.authorization.internal.AuthorizedDefaultServlet;
@@ -93,6 +96,7 @@
import org.eclipse.basyx.vab.exception.provider.ProviderException;
import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
import org.eclipse.basyx.vab.modelprovider.VABPathTools;
+import org.eclipse.basyx.vab.protocol.http.server.BaSyxChildContext;
import org.eclipse.basyx.vab.protocol.http.server.BaSyxContext;
import org.eclipse.basyx.vab.protocol.http.server.BaSyxHTTPServer;
import org.eclipse.basyx.vab.protocol.http.server.VABHTTPInterface;
@@ -107,7 +111,6 @@
*
* @author schnicke, espen, fried, fischer, danish, wege
*/
-@SuppressWarnings("deprecation")
public class AASServerComponent implements IComponent {
private static Logger logger = LoggerFactory.getLogger(AASServerComponent.class);
@@ -121,16 +124,17 @@ public class AASServerComponent implements IComponent {
private BaSyxMongoDBConfiguration mongoDBConfig;
private BaSyxSecurityConfiguration securityConfig;
- private List aasServerFeatureList = new ArrayList();
-
- // Initial AASBundle
- protected Collection aasBundles;
+ private List aasServerFeatureList = new ArrayList<>();
+ protected List> aasBundles = new ArrayList<>();
private IAASAggregator aggregator;
// Watcher for AAS Aggregator functionality
private boolean isAASXUploadEnabled = false;
private static final String PREFIX_SUBMODEL_PATH = "/aas/submodels/";
+ private static final String AASX_RES_FILE_CONTEXT_PATH = AASXToMetamodelConverter.TEMP_DIRECTORY;
+ private static final String AASX_RES_FILE_DOCBASE_PATH = VABPathTools.append(System.getProperty("java.io.tmpdir"), AASX_RES_FILE_CONTEXT_PATH);
+ private static final String AASX_RES_FILE_SERVLET_MAPPING_PATTERN = "/*";
/**
* Constructs an empty AAS server using the passed context
@@ -210,7 +214,8 @@ public void setRegistry(IAASRegistry registry) {
* The bundles that will be loaded during startup
*/
public void setAASBundles(Collection aasBundles) {
- this.aasBundles = aasBundles;
+ this.aasBundles = new ArrayList<>();
+ this.aasBundles.add(aasBundles);
}
/**
@@ -220,7 +225,9 @@ public void setAASBundles(Collection aasBundles) {
* The bundle that will be loaded during startup
*/
public void setAASBundle(AASBundle aasBundle) {
- this.aasBundles = Collections.singleton(aasBundle);
+ this.aasBundles = new ArrayList<>();
+ Collection firstBundleSet = Collections.singleton(aasBundle);
+ this.aasBundles.add(firstBundleSet);
}
/**
@@ -251,11 +258,12 @@ public void startComponent() {
// An initial AAS has been loaded from the drive?
if (aasBundles != null) {
- // 1. Also provide the files
- context.addServletMapping("/files/*", createDefaultServlet());
+ createBasyxResourceDirectoryIfNotExists();
+
+ addAasxFilesResourceServlet(context);
// 2. Fix the file paths according to the servlet configuration
- modifyFilePaths(contextConfig.getHostname(), contextConfig.getPort(), contextConfig.getContextPath());
+ modifyFilePaths(contextConfig.getHostname(), contextConfig.getPort(), getRootFilePathWithContext(contextConfig.getContextPath()));
registerWhitelistedSubmodels();
}
@@ -267,6 +275,10 @@ public void startComponent() {
registerPreexistingAASAndSMIfPossible();
}
+ private String getRootFilePathWithContext(String contextPath) {
+ return VABPathTools.append(contextPath, AASX_RES_FILE_CONTEXT_PATH);
+ }
+
private DefaultServlet createDefaultServlet() {
if (aasConfig.isAuthorizationEnabled()) {
final AuthorizedDefaultServletParams> params = getAuthorizedDefaultServletParams();
@@ -543,17 +555,18 @@ private Set loadBundleFromJSON(String jsonPath) throws IOException {
return new JSONAASBundleFactory(jsonContent).create();
}
- private static Set loadBundleFromAASX(String aasxPath) throws IOException, ParserConfigurationException, SAXException, InvalidFormatException, URISyntaxException {
+ private static Set loadBundleFromAASX(String aasxPath, String childFilePath) throws IOException, ParserConfigurationException, SAXException, InvalidFormatException, URISyntaxException {
logger.info("Loading aas from aasx \"" + aasxPath + "\"");
// Instantiate the aasx package manager
- AASXToMetamodelConverter packageManager = new AASXPackageManager(aasxPath);
-
- // Unpack the files referenced by the aas
- packageManager.unzipRelatedFiles();
+ try (AASXToMetamodelConverter packageManager = new AASXToMetamodelConverter(aasxPath)) {
+ // Unpack the files referenced by the aas
+ packageManager.unzipRelatedFilesToChildPath(childFilePath);
- // Retrieve the aas from the package
- return packageManager.retrieveAASBundles();
+ // Retrieve the aas from the package
+ return packageManager.retrieveAASBundles();
+ }
+
}
private void addAASServerFeaturesToContext(BaSyxContext context) {
@@ -562,13 +575,21 @@ private void addAASServerFeaturesToContext(BaSyxContext context) {
}
}
+ private Collection getFlatAASBundles() {
+ Collection result = new ArrayList();
+ for (Collection bundle : this.aasBundles) {
+ result.addAll(bundle);
+ }
+ return result;
+ }
+
private VABHTTPInterface> createAggregatorServlet() {
aggregator = createAASAggregator();
loadAASBundles();
if (aasBundles != null) {
try (final var ignored = ElevatedCodeAuthentication.enterElevatedCodeAuthenticationArea()) {
- AASBundleHelper.integrate(aggregator, aasBundles);
+ AASBundleHelper.integrate(aggregator, getFlatAASBundles());
}
}
@@ -614,7 +635,7 @@ private List createAASServerDecoratorList() {
}
private void loadAASBundles() {
- if (aasBundles != null) {
+ if (!aasBundles.isEmpty()) {
return;
}
@@ -622,22 +643,31 @@ private void loadAASBundles() {
aasBundles = loadAASFromSource(aasSources);
}
- private Set loadAASFromSource(List aasSources) {
+ private List> loadAASFromSource(List aasSources) {
if (aasSources.isEmpty()) {
- return Collections.emptySet();
+ return new ArrayList<>();
}
- Set aasBundlesSet = new HashSet<>();
+ List> aasBundlesSet = new ArrayList<>();
- aasSources.stream().map(this::loadBundleFromFile).forEach(aasBundlesSet::addAll);
+ for (int i = 0; i < aasSources.size(); i++) {
+ String aasSource = aasSources.get(i);
+ String subFilePath = getAASXFileSubPath(i);
+ Set loadedBundles = loadBundleFromFile(aasSource, subFilePath);
+ aasBundlesSet.add(loadedBundles);
+ }
return aasBundlesSet;
}
- private Set loadBundleFromFile(String aasSource) {
+ private String getAASXFileSubPath(int aasxIndex) {
+ return "aasx" + Integer.toString(aasxIndex);
+ }
+
+ private Set loadBundleFromFile(String aasSource, String childFilePath) {
try {
if (aasSource.endsWith(".aasx")) {
- return loadBundleFromAASX(aasSource);
+ return loadBundleFromAASX(aasSource, childFilePath);
} else if (aasSource.endsWith(".json")) {
return loadBundleFromJSON(aasSource);
} else if (aasSource.endsWith(".xml")) {
@@ -730,7 +760,8 @@ private String getSMEndpoint(IIdentifier smId) {
}
private String getSMIdShortFromSMId(IIdentifier smId) {
- for (AASBundle bundle : aasBundles) {
+ Collection flatAasBundles = getFlatAASBundles();
+ for (AASBundle bundle : flatAasBundles) {
for (ISubmodel sm : bundle.getSubmodels()) {
if (smId.getId().equals(sm.getIdentification().getId())) {
return sm.getIdShort();
@@ -741,7 +772,8 @@ private String getSMIdShortFromSMId(IIdentifier smId) {
}
private String getAASIdFromSMId(IIdentifier smId) {
- for (AASBundle bundle : aasBundles) {
+ Collection flatAasBundles = getFlatAASBundles();
+ for (AASBundle bundle : flatAasBundles) {
for (ISubmodel sm : bundle.getSubmodels()) {
if (smId.getId().equals(sm.getIdentification().getId())) {
return bundle.getAAS().getIdentification().getId();
@@ -756,11 +788,18 @@ private String getAASIdFromSMId(IIdentifier smId) {
* configuration
*/
private void modifyFilePaths(String hostName, int port, String rootPath) {
- rootPath = rootPath + "/files";
- for (AASBundle bundle : aasBundles) {
+ for (int i = 0; i < aasBundles.size(); i++) {
+ Collection bundleSet = aasBundles.get(i);
+ String bundleFileRootPath = VABPathTools.concatenatePaths(rootPath, getAASXFileSubPath(i), "files");
+ modifyFilePathsInBundleSet(bundleSet, hostName, port, bundleFileRootPath);
+ }
+ }
+
+ private void modifyFilePathsInBundleSet(Collection bundleSet, String hostName, int port, String bundleFileRootPath) {
+ for (AASBundle bundle : bundleSet) {
Set submodels = bundle.getSubmodels();
for (ISubmodel sm : submodels) {
- SubmodelFileEndpointLoader.setRelativeFileEndpoints(sm, hostName, port, rootPath);
+ SubmodelFileEndpointLoader.setRelativeFileEndpoints(sm, hostName, port, bundleFileRootPath);
}
}
}
@@ -769,10 +808,41 @@ private String getMqttAASClientId() {
if (aasBundles == null || aasBundles.isEmpty()) {
return "defaultNoShellId";
}
- return aasBundles.stream().findFirst().get().getAAS().getIdShort();
+ Collection firstBundleSet = aasBundles.get(0);
+ if (firstBundleSet == null || firstBundleSet.isEmpty()) {
+ return "defaultNoShellId";
+ }
+ return firstBundleSet.stream().findFirst().get().getAAS().getIdShort();
}
private String getMqttSubmodelClientId() {
return getMqttAASClientId() + "/submodelAggregator";
}
+
+ private void addAasxFilesResourceServlet(BaSyxContext context) {
+ HttpServlet httpServlet = createDefaultServlet();
+
+ String childContextPath = VABPathTools.append(contextConfig.getContextPath(), AASX_RES_FILE_CONTEXT_PATH);
+ Context childContext = createChildContextForAasxResourceFiles(childContextPath, AASX_RES_FILE_DOCBASE_PATH);
+
+ context.addChildContext(new BaSyxChildContext(childContext, httpServlet, AASX_RES_FILE_SERVLET_MAPPING_PATTERN));
+ }
+
+ private Context createChildContextForAasxResourceFiles(String childContextPath, String childDocbasePath) {
+ Context childContext = new StandardContext();
+ childContext.setPath(childContextPath);
+ childContext.setDocBase(childDocbasePath);
+ childContext.addLifecycleListener(new Tomcat.FixContextListener());
+ return childContext;
+ }
+
+ private void createBasyxResourceDirectoryIfNotExists() {
+ File directory = new File(AASX_RES_FILE_DOCBASE_PATH);
+
+ if (directory.exists())
+ return;
+
+ directory.mkdir();
+ }
+
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/authorization/internal/PathTargetInformation.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/authorization/internal/PathTargetInformation.java
index 9facfed6..a6a1ac1f 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/authorization/internal/PathTargetInformation.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/authorization/internal/PathTargetInformation.java
@@ -31,7 +31,6 @@
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
-import org.eclipse.basyx.extensions.shared.authorization.internal.TagTargetInformation;
import org.eclipse.basyx.extensions.shared.authorization.internal.TargetInformation;
import com.fasterxml.jackson.annotation.JsonCreator;
@@ -73,7 +72,7 @@ public boolean equals(final Object o) {
return true;
}
- if (!(o instanceof TagTargetInformation)) {
+ if (!(o instanceof PathTargetInformation)) {
return false;
}
@@ -89,6 +88,6 @@ public int hashCode() {
@Override
public String toString() {
- return new StringBuilder("BaSyxObjectTargetInformation{").append("tag='").append(path).append('\'').append('}').toString();
+ return new StringBuilder("PathTargetInformation{").append("path='").append(path).append('\'').append('}').toString();
}
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/configuration/BaSyxAASServerConfiguration.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/configuration/BaSyxAASServerConfiguration.java
index 0402af6d..bb4b6a49 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/configuration/BaSyxAASServerConfiguration.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/configuration/BaSyxAASServerConfiguration.java
@@ -27,6 +27,7 @@
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -70,10 +71,11 @@ public class BaSyxAASServerConfiguration extends BaSyxConfiguration {
public static final String DEFAULT_CLIENT_SCOPES = "[]";
public static final String DEFAULT_PROPERTY_DELEGATION = FEATURE_ENABLED;
-
// Configuration keys
public static final String REGISTRY = "registry.path";
+ @Deprecated
public static final String HOSTPATH = "registry.host";
+ public static final String HOSTPATH_NEW = "aas.externalurl";
public static final String SUBMODELS = "registry.submodels";
public static final String ID = "aas.id";
public static final String BACKEND = "aas.backend";
@@ -100,7 +102,7 @@ public static Map getDefaultProperties() {
defaultProps.put(BACKEND, DEFAULT_BACKEND);
defaultProps.put(SOURCE, DEFAULT_SOURCE);
defaultProps.put(REGISTRY, DEFAULT_REGISTRY);
- defaultProps.put(HOSTPATH, DEFAULT_HOSTPATH);
+ defaultProps.put(HOSTPATH_NEW, DEFAULT_HOSTPATH);
defaultProps.put(SUBMODELS, DEFAULT_SUBMODELS);
defaultProps.put(EVENTS, DEFAULT_EVENTS);
defaultProps.put(AASX_UPLOAD, DEFAULT_AASX_UPLOAD);
@@ -117,7 +119,7 @@ public static Map getDefaultProperties() {
* Empty Constructor - use default values
*/
public BaSyxAASServerConfiguration() {
- super(getDefaultProperties());
+ super(getDefaultProperties(), getPropertiesExcludedFromLogging());
}
/**
@@ -129,7 +131,7 @@ public BaSyxAASServerConfiguration() {
* The file source for the AASServer (e.g. an .aasx file)
*/
public BaSyxAASServerConfiguration(AASServerBackend backend, String source) {
- super(getDefaultProperties());
+ this();
setAASBackend(backend);
setAASSourceAsList(source);
}
@@ -171,14 +173,11 @@ public BaSyxAASServerConfiguration(AASServerBackend backend, String source, Stri
* Constructor with predefined value map
*/
public BaSyxAASServerConfiguration(Map values) {
- super(values);
+ super(values, getPropertiesExcludedFromLogging());
}
public void loadFromEnvironmentVariables() {
- String[] properties = {
- REGISTRY, BACKEND, SOURCE, EVENTS, HOSTPATH, AASX_UPLOAD, AUTHORIZATION, TOKEN_ENDPOINT,
- CLIENT_ID, CLIENT_SECRET, CLIENT_SCOPES, PROPERTY_DELEGATION, ID
- };
+ String[] properties = { REGISTRY, BACKEND, SOURCE, EVENTS, HOSTPATH, HOSTPATH_NEW, AASX_UPLOAD, AUTHORIZATION, TOKEN_ENDPOINT, CLIENT_ID, CLIENT_SECRET, CLIENT_SCOPES, PROPERTY_DELEGATION, ID };
loadFromEnvironmentVariables(ENV_PREFIX, properties);
}
@@ -186,17 +185,17 @@ public void loadFromDefaultSource() {
loadFileOrDefaultResource(DEFAULT_FILE_KEY, DEFAULT_CONFIG_PATH);
loadFromEnvironmentVariables();
}
-
+
public IAuthorizationSupplier configureAndGetAuthorizationSupplier() {
- if(!isAuthorizationCredentialsForSecuredRegistryConfigured()) {
+ if (!isAuthorizationCredentialsForSecuredRegistryConfigured()) {
throw new AuthorizationConfigurationException("Authorization credentials for the secured registry is not configured");
}
-
+
return new OAuth2ClientCredentialsBasedAuthorizationSupplier(getTokenEndpoint(), getClientId(), getClientSecret(), getClientScopes());
}
-
+
public String getAASId() {
- return getProperty(ID);
+ return getProperty(ID);
}
public AASServerBackend getAASBackend() {
@@ -282,11 +281,15 @@ public void setSubmodels(List submodels) {
}
public String getHostpath() {
- return getProperty(HOSTPATH);
+ if (getProperty(HOSTPATH_NEW).equals("") && getProperty(HOSTPATH) != null) {
+ return getProperty(HOSTPATH);
+ } else {
+ return getProperty(HOSTPATH_NEW);
+ }
}
public void setHostpath(String hostPath) {
- setProperty(HOSTPATH, hostPath);
+ setProperty(HOSTPATH_NEW, hostPath);
}
@SuppressWarnings("unchecked")
@@ -298,7 +301,7 @@ private List parseFromJson(String property) {
return fromJson;
}
}
-
+
private T parseFromJson(String property, Class classTypeT) {
T fromJson = new Gson().fromJson(property, (Type) classTypeT);
if (fromJson == null) {
@@ -327,7 +330,7 @@ public void disableAuthorization() {
public String getTokenEndpoint() {
return getProperty(TOKEN_ENDPOINT);
}
-
+
public void setTokenEndpoint(String tokenEndpoint) {
setProperty(TOKEN_ENDPOINT, tokenEndpoint);
}
@@ -335,7 +338,7 @@ public void setTokenEndpoint(String tokenEndpoint) {
public String getClientId() {
return getProperty(CLIENT_ID);
}
-
+
public void setClientId(String clientId) {
setProperty(CLIENT_ID, clientId);
}
@@ -343,7 +346,7 @@ public void setClientId(String clientId) {
public String getClientSecret() {
return getProperty(CLIENT_SECRET);
}
-
+
public void setClientSecret(String clientSecret) {
setProperty(CLIENT_SECRET, clientSecret);
}
@@ -352,11 +355,11 @@ public void setClientSecret(String clientSecret) {
public Set getClientScopes() {
return parseFromJson(getProperty(CLIENT_SCOPES), Set.class);
}
-
+
public void setClientScopes(String clientScopes) {
setProperty(CLIENT_SCOPES, clientScopes);
}
-
+
public void enablePropertyDelegation() {
setProperty(PROPERTY_DELEGATION, FEATURE_ENABLED);
}
@@ -364,11 +367,11 @@ public void enablePropertyDelegation() {
public void disablePropertyDelegation() {
setProperty(PROPERTY_DELEGATION, FEATURE_DISABLED);
}
-
+
public boolean isPropertyDelegationEnabled() {
return getProperty(PROPERTY_DELEGATION).equals(FEATURE_ENABLED);
}
-
+
public boolean isAuthorizationCredentialsForSecuredRegistryConfigured() {
return isTokenEndpointConfigured() && isClientIdConfigured() && isClientSecretConfigured() && isScopeConfigured();
}
@@ -376,7 +379,7 @@ public boolean isAuthorizationCredentialsForSecuredRegistryConfigured() {
private boolean isTokenEndpointConfigured() {
return getProperty(TOKEN_ENDPOINT) != null && !getProperty(TOKEN_ENDPOINT).isEmpty();
}
-
+
private boolean isClientIdConfigured() {
return getProperty(CLIENT_ID) != null && !getProperty(CLIENT_ID).isEmpty();
}
@@ -384,8 +387,13 @@ private boolean isClientIdConfigured() {
private boolean isClientSecretConfigured() {
return getProperty(CLIENT_SECRET) != null && !getProperty(CLIENT_SECRET).isEmpty();
}
-
+
private boolean isScopeConfigured() {
return getProperty(CLIENT_SCOPES) != null && !getProperty(CLIENT_SCOPES).isEmpty();
}
+
+ private static List getPropertiesExcludedFromLogging() {
+ return Collections.singletonList(CLIENT_SECRET);
+ }
+
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/internal/StorageSubmodelAPI.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/internal/StorageSubmodelAPI.java
new file mode 100644
index 00000000..0df5f9f8
--- /dev/null
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/internal/StorageSubmodelAPI.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.basyx.components.aas.internal;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.basyx.extensions.internal.storage.BaSyxStorageAPI;
+import org.eclipse.basyx.submodel.metamodel.api.submodelelement.ISubmodelElement;
+import org.eclipse.basyx.submodel.metamodel.api.submodelelement.operation.IOperation;
+import org.eclipse.basyx.submodel.metamodel.facade.submodelelement.SubmodelElementFacadeFactory;
+import org.eclipse.basyx.submodel.metamodel.map.Submodel;
+import org.eclipse.basyx.submodel.metamodel.map.submodelelement.operation.Operation;
+import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPI;
+import org.eclipse.basyx.submodel.restapi.operation.DelegatedInvocationManager;
+import org.eclipse.basyx.submodel.restapi.vab.VABSubmodelAPI;
+import org.eclipse.basyx.vab.exception.provider.MalformedRequestException;
+import org.eclipse.basyx.vab.modelprovider.VABPathTools;
+import org.eclipse.basyx.vab.modelprovider.lambda.VABLambdaProvider;
+
+/**
+ * Abstract submodel api for storage backends.
+ *
+ * @author fischer
+ *
+ */
+public abstract class StorageSubmodelAPI implements ISubmodelAPI {
+ protected BaSyxStorageAPI storageApi;
+ private String identificationId;
+ private DelegatedInvocationManager invocationManager;
+
+ protected StorageSubmodelAPI(BaSyxStorageAPI storageAPI, String identificationId, DelegatedInvocationManager invocatonManager) {
+ this.storageApi = storageAPI;
+ this.identificationId = identificationId;
+ this.invocationManager = invocatonManager;
+ }
+
+ public String getSubmodelId() {
+ return identificationId;
+ }
+
+ /**
+ * Sets the submodel id, so that this API points to the submodel with smId. Can
+ * be changed to point to a different submodel in the database.
+ *
+ * @param identificationId
+ */
+ public void setSubmodelId(String identificationId) {
+ this.identificationId = identificationId;
+ }
+
+ /**
+ * Depending on whether the model is already in the db, this method inserts or
+ * replaces the existing data. The new submodel id for this API is taken from
+ * the given submodel.
+ *
+ * @param submodel
+ */
+ public void setSubmodel(Submodel submodel) {
+ String submodelId = submodel.getIdentification().getId();
+ setSubmodelId(submodelId);
+ storageApi.update(submodel, submodelId);
+ }
+
+ @Override
+ public Submodel getSubmodel() {
+ return storageApi.retrieve(identificationId);
+ }
+
+ @Override
+ public void addSubmodelElement(ISubmodelElement elem) {
+ Submodel submodel = (Submodel) getSubmodel();
+ submodel.addSubmodelElement(elem);
+ storageApi.update(submodel, identificationId);
+ }
+
+ @Override
+ public void addSubmodelElement(String idShortPath, ISubmodelElement elem) {
+ VABSubmodelAPI api = new VABSubmodelAPI(new VABLambdaProvider(getSubmodel()));
+ api.addSubmodelElement(idShortPath, elem);
+ storageApi.update(api.getSubmodel(), identificationId);
+ }
+
+
+ @Override
+ public ISubmodelElement getSubmodelElement(String idShortPath) {
+ VABSubmodelAPI api = new VABSubmodelAPI(new VABLambdaProvider(getSubmodel()));
+ return api.getSubmodelElement(idShortPath);
+ }
+
+ @Override
+ public void deleteSubmodelElement(String idShortPath) {
+ VABSubmodelAPI api = new VABSubmodelAPI(new VABLambdaProvider(getSubmodel()));
+ api.deleteSubmodelElement(idShortPath);
+ storageApi.update(api.getSubmodel(), identificationId);
+ }
+
+
+ @Override
+ public Collection getOperations() {
+ Submodel submodel = (Submodel) getSubmodel();
+ return submodel.getOperations().values();
+ }
+
+ @Override
+ public Collection getSubmodelElements() {
+ Submodel submodel = (Submodel) getSubmodel();
+ return submodel.getSubmodelElements().values();
+ }
+
+ @Override
+ public void updateSubmodelElement(String idShortPath, Object newValue) {
+ VABSubmodelAPI api = new VABSubmodelAPI(new VABLambdaProvider(getSubmodel()));
+ api.updateSubmodelElement(idShortPath, newValue);
+ storageApi.update(api.getSubmodel(), identificationId);
+ }
+
+
+ @Override
+ public Object getSubmodelElementValue(String idShortPath) {
+ VABSubmodelAPI api = new VABSubmodelAPI(new VABLambdaProvider(getSubmodel()));
+ return api.getSubmodelElementValue(idShortPath);
+ }
+
+ @Deprecated
+ @SuppressWarnings("unchecked")
+ protected Object unwrapParameter(Object parameter) {
+ if (parameter instanceof Map, ?>) {
+ Map map = (Map) parameter;
+ // Parameters have a strictly defined order and may not be omitted at all.
+ // Enforcing the structure with valueType is ok, but we should unwrap null
+ // values, too.
+ if (map.get("valueType") != null && map.containsKey("value")) {
+ return map.get("value");
+ }
+ }
+ return parameter;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object invokeOperation(String idShortPath, Object... params) {
+ Operation operation = (Operation) SubmodelElementFacadeFactory.createSubmodelElement((Map) getSubmodelElement(idShortPath));
+ if (!DelegatedInvocationManager.isDelegatingOperation(operation)) {
+ throw new MalformedRequestException("This backend supports only delegating operations.");
+ }
+ return invocationManager.invokeDelegatedOperation(operation, params);
+ }
+
+ @Override
+ public Object invokeAsync(String idShortPath, Object... params) {
+ List idShorts = idShortsPathAsList(idShortPath);
+ return invokeNestedOperationAsync(idShorts, params);
+ }
+
+ private List idShortsPathAsList(String idShortPath) {
+ String[] splittedIdShortPath = VABPathTools.splitPath(idShortPath);
+ return Arrays.asList(splittedIdShortPath);
+ }
+
+ private Object invokeNestedOperationAsync(List idShorts, Object... params) {
+ throw new MalformedRequestException("Invoke not supported by this backend");
+ }
+
+ @Override
+ public Object getOperationResult(String idShort, String requestId) {
+ throw new MalformedRequestException("Invoke not supported by this backend");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public java.io.File getSubmodelElementFile(String idShortPath) {
+ Map submodelElement = (Map) getSubmodelElement(idShortPath);
+ String parentKey = getSubmodel().getIdentification().getId();
+ return storageApi.getFile(idShortPath, parentKey, submodelElement);
+ }
+
+ @Override
+ public void uploadSubmodelElementFile(String idShortPath, InputStream fileStream) {
+ VABSubmodelAPI api = new VABSubmodelAPI(new VABLambdaProvider(getSubmodel()));
+ ISubmodelElement element = api.getSubmodelElement(idShortPath);
+ String fileName = storageApi.writeFile(idShortPath, getSubmodel().getIdentification().getId(), fileStream, element);
+ updateSubmodelElement(idShortPath, fileName);
+ }
+
+}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAPI.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAPI.java
index 5ee5e2e4..e99ce950 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAPI.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAPI.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2021 the Eclipse BaSyx Authors
+ * Copyright (C) 2021, 2023 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -24,85 +24,83 @@
******************************************************************************/
package org.eclipse.basyx.components.aas.mongodb;
-import static org.springframework.data.mongodb.core.query.Criteria.where;
-import static org.springframework.data.mongodb.core.query.Query.query;
-
import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
+import java.util.Optional;
import org.eclipse.basyx.aas.metamodel.api.IAssetAdministrationShell;
import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;
import org.eclipse.basyx.aas.restapi.api.IAASAPI;
import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPI;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPIFactory;
import org.eclipse.basyx.submodel.metamodel.api.reference.IKey;
import org.eclipse.basyx.submodel.metamodel.api.reference.IReference;
-import org.eclipse.basyx.submodel.metamodel.map.identifier.Identifier;
-import org.eclipse.basyx.submodel.metamodel.map.qualifier.Identifiable;
-import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
-import org.springframework.data.mongodb.core.MongoOperations;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.query.Query;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.mongodb.client.MongoClient;
-import com.mongodb.client.MongoClients;
/**
* Implements the IAASAPI for a mongoDB backend.
*
- * @author espen
+ * @author espen, jungjan, witt
*/
public class MongoDBAASAPI implements IAASAPI {
+ private Logger logger = LoggerFactory.getLogger(getClass());
private static final String DEFAULT_CONFIG_PATH = "mongodb.properties";
- private static final String AASIDPATH = Identifiable.IDENTIFICATION + "." + Identifier.ID;
- protected BaSyxMongoDBConfiguration config;
- protected MongoOperations mongoOps;
- protected String collection;
- protected String aasId;
+ protected String collectionName;
+ private MongoDBBaSyxStorageAPI storageApi;
+ private String shellIdentificationId;
/**
* Receives the path of the configuration.properties file in its constructor.
*
* @param config
- * @deprecated Use the new constructor using a MongoClient
*/
- @Deprecated
- public MongoDBAASAPI(BaSyxMongoDBConfiguration config, String aasId) {
- this(config, aasId, MongoClients.create(config.getConnectionUrl()));
+ public MongoDBAASAPI(BaSyxMongoDBConfiguration config, String shellIdentificationId, MongoClient client) {
+ this(MongoDBBaSyxStorageAPIFactory.create(config.getAASCollection(), AssetAdministrationShell.class, config, client), shellIdentificationId);
+ }
+
+ public MongoDBAASAPI(MongoDBBaSyxStorageAPI mongoDBStorageAPI, String shellIdentificationId) {
+ super();
+ this.storageApi = mongoDBStorageAPI;
+ this.shellIdentificationId = shellIdentificationId;
}
/**
- * Receives the path of the configuration.properties file in its constructor.
- *
- * @param config
+ * Receives the path of the .properties file in its constructor from a resource.
*/
- public MongoDBAASAPI(BaSyxMongoDBConfiguration config, String aasId, MongoClient client) {
- this.setConfiguration(config, client);
- this.setAASId(aasId);
+ public MongoDBAASAPI(String resourceConfigPath, String shellIdentificationId, MongoClient client) {
+ this(MongoDBBaSyxStorageAPIFactory.create(configFromResource(resourceConfigPath).getSubmodelCollection(), AssetAdministrationShell.class, configFromResource(resourceConfigPath), client), shellIdentificationId);
}
/**
- * Receives the path of the .properties file in its constructor from a resource.
+ * Constructor using default MongoDB connections
+ */
+ public MongoDBAASAPI(String shellIdentificationId, MongoClient client) {
+ this(DEFAULT_CONFIG_PATH, shellIdentificationId, client);
+ }
+
+ /**
+ * Receives the path of the configuration.properties file in its constructor.
*
+ * @param config
* @deprecated Use the new constructor using a MongoClient
*/
@Deprecated
- public MongoDBAASAPI(String resourceConfigPath, String aasId) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- this.setConfiguration(config);
- this.setAASId(aasId);
+ public MongoDBAASAPI(BaSyxMongoDBConfiguration config, String shellIdentificationId) {
+ this(MongoDBBaSyxStorageAPIFactory.create(config.getAASCollection(), AssetAdministrationShell.class, config), shellIdentificationId);
}
/**
* Receives the path of the .properties file in its constructor from a resource.
+ *
+ * @deprecated Use the new constructor using a MongoClient
*/
- public MongoDBAASAPI(String resourceConfigPath, String aasId, MongoClient client) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- this.setConfiguration(config, client);
- this.setAASId(aasId);
+ @Deprecated
+ public MongoDBAASAPI(String resourceConfigPath, String shellIdentificationId) {
+ this(MongoDBBaSyxStorageAPIFactory.create(configFromResource(resourceConfigPath).getSubmodelCollection(), AssetAdministrationShell.class, configFromResource(resourceConfigPath)), shellIdentificationId);
}
/**
@@ -111,113 +109,94 @@ public MongoDBAASAPI(String resourceConfigPath, String aasId, MongoClient client
* @deprecated Use the new constructor using a MongoClient
*/
@Deprecated
- public MongoDBAASAPI(String aasId) {
- this(DEFAULT_CONFIG_PATH, aasId);
+ public MongoDBAASAPI(String shellIdentificationId) {
+ this(DEFAULT_CONFIG_PATH, shellIdentificationId);
}
- /**
- * Constructor using default MongoDB connections
- */
- public MongoDBAASAPI(String aasId, MongoClient client) {
- this(DEFAULT_CONFIG_PATH, aasId, client);
+ private static BaSyxMongoDBConfiguration configFromResource(String resourceConfigPath) {
+ BaSyxMongoDBConfiguration config = new BaSyxMongoDBConfiguration();
+ config.loadFromResource(resourceConfigPath);
+ return config;
}
- @Deprecated
+ /**
+ * This Method enables to switch the BaSyxMongoDBConfiguration at runtime
+ *
+ * @param config
+ */
public void setConfiguration(BaSyxMongoDBConfiguration config) {
- MongoClient client = MongoClients.create(config.getConnectionUrl());
- setConfiguration(config, client);
+ this.collectionName = config.getAASCollection();
+ MongoDBBaSyxStorageAPIFactory storageApiFactory = new MongoDBBaSyxStorageAPIFactory<>(config, AssetAdministrationShell.class, this.collectionName);
+ this.storageApi = storageApiFactory.create();
}
+ /**
+ * This Method enables to switch the BaSyxMongoDBConfiguration at runtime
+ *
+ * @param config
+ */
public void setConfiguration(BaSyxMongoDBConfiguration config, MongoClient client) {
- this.config = config;
- this.mongoOps = new MongoTemplate(client, config.getDatabase());
- this.collection = config.getAASCollection();
+ this.collectionName = config.getAASCollection();
+ MongoDBBaSyxStorageAPIFactory storageApiFactory = new MongoDBBaSyxStorageAPIFactory<>(config, AssetAdministrationShell.class, this.collectionName, client);
+ this.storageApi = storageApiFactory.create();
}
/**
- * Sets the aas id, so that this API points to the aas with aasId. Can be
- * changed to point to a different aas in the database.
+ * Sets the shellIdentificationId, so that this API points to the shell with
+ * shellIdentificationId. Can be changed to point to a different shell in the
+ * database.
*
- * @param aasId
+ * @param shellIdentificationId
*/
- public void setAASId(String aasId) {
- this.aasId = aasId;
+ public void setAASId(String shellIdentificationId) {
+ this.shellIdentificationId = shellIdentificationId;
}
/**
* Depending on whether the model is already in the db, this method inserts or
- * replaces the existing data. The new aas id for this API is taken from the
- * given aas.
+ * replaces the existing data. The new shell id for this API is taken from the
+ * given shell.
*
- * @param aas
+ * @param shell
*/
- public void setAAS(AssetAdministrationShell aas) {
- String id = aas.getIdentification().getId();
+ public void setAAS(AssetAdministrationShell shell) {
+ String id = shell.getIdentification().getId();
this.setAASId(id);
-
- Query hasId = query(where(AASIDPATH).is(aasId));
- // Try to replace if already present - otherwise: insert it
- Object replaced = mongoOps.findAndReplace(hasId, aas, collection);
- if (replaced == null) {
- mongoOps.insert(aas, collection);
- }
- // Remove mongoDB-specific map attribute from AAS.
- // mongoOps modify aas on save - thus _id has to be removed here...
- aas.remove("_id");
+ storageApi.createOrUpdate(shell);
}
@Override
public IAssetAdministrationShell getAAS() {
- Query hasId = query(where(AASIDPATH).is(aasId));
- AssetAdministrationShell aas = mongoOps.findOne(hasId, AssetAdministrationShell.class, collection);
- if (aas == null) {
- throw new ResourceNotFoundException("The AAS " + aasId + " could not be found in the database.");
- }
- // Remove mongoDB-specific map attribute from AAS
- aas.remove("_id");
- return aas;
+ return storageApi.retrieve(shellIdentificationId);
}
@Override
- public void addSubmodel(IReference submodel) {
- // Get AAS from db
- Query hasId = query(where(AASIDPATH).is(aasId));
- AssetAdministrationShell aas = mongoOps.findOne(hasId, AssetAdministrationShell.class, collection);
- if (aas == null) {
- throw new ResourceNotFoundException("The AAS " + aasId + " could not be found in the database.");
- }
- // Add reference
- aas.addSubmodelReference(submodel);
- // Update db entry
- mongoOps.findAndReplace(hasId, aas, collection);
+ public void addSubmodel(IReference submodelReference) {
+ AssetAdministrationShell shell = (AssetAdministrationShell) getAAS();
+ shell.addSubmodelReference(submodelReference);
+ storageApi.update(shell, shellIdentificationId);
}
@Override
- public void removeSubmodel(String id) {
- // Get AAS from db
- Query hasId = query(where(AASIDPATH).is(aasId));
- AssetAdministrationShell aas = mongoOps.findOne(hasId, AssetAdministrationShell.class, collection);
- if (aas == null) {
- throw new ResourceNotFoundException("The AAS " + aasId + " could not be found in the database.");
- }
- // Remove reference
- Collection smReferences = aas.getSubmodelReferences();
- // Reference to submodel could be either by idShort (=> local) or directly via
- // its identifier
- for (Iterator iterator = smReferences.iterator(); iterator.hasNext();) {
- IReference ref = iterator.next();
- List keys = ref.getKeys();
- IKey lastKey = keys.get(keys.size() - 1);
- String idValue = lastKey.getValue();
- // remove this reference, if the last key points to the submodel
- if (idValue.equals(id)) {
- iterator.remove();
- break;
- }
+ public void removeSubmodel(String submodelIdShort) {
+ AssetAdministrationShell shell = (AssetAdministrationShell) this.getAAS();
+ Collection submodelReferences = shell.getSubmodelReferences();
+
+ Optional toBeRemoved = submodelReferences.stream().filter(submodelReference -> getLastSubmodelReferenceKey(submodelReference).getValue().equals(submodelIdShort)).findFirst();
+ if (!toBeRemoved.isPresent() || toBeRemoved.isEmpty()) {
+ logger.warn("Submodel reference could not be removed. Shell with identification id '{}' does not contain submodel with idShort '{}'.", shell.getIdentification().getId(), submodelIdShort);
+ return;
}
- aas.setSubmodelReferences(smReferences);
- // Update db entry
- mongoOps.findAndReplace(hasId, aas, collection);
+ submodelReferences.remove(toBeRemoved.get());
+ shell.setSubmodelReferences(submodelReferences);
+ storageApi.update(shell, submodelIdShort);
}
+ private IKey getLastSubmodelReferenceKey(IReference submodelReference) {
+ return submodelReference.getKeys().get(getLastSubmodelReferenceReferenceIndex(submodelReference));
+ }
+
+ private int getLastSubmodelReferenceReferenceIndex(IReference submodelReference) {
+ return submodelReference.getKeys().size() - 1;
+ }
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAPIFactory.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAPIFactory.java
index 3fabc1d6..8f0f70ca 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAPIFactory.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAPIFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2022 the Eclipse BaSyx Authors
+ * Copyright (C) 2022, 2023 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -28,37 +28,46 @@
import org.eclipse.basyx.aas.restapi.api.IAASAPI;
import org.eclipse.basyx.aas.restapi.api.IAASAPIFactory;
import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPI;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPIFactory;
+import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
import com.mongodb.client.MongoClient;
-import com.mongodb.client.MongoClients;
/**
*
* Factory for creating a MongoDBAASAPI
*
- * @author fried
+ * @author fried, jungjan, witt
*
*/
public class MongoDBAASAPIFactory implements IAASAPIFactory {
- private BaSyxMongoDBConfiguration config;
- private MongoClient client;
+ private MongoDBBaSyxStorageAPI storageAPI;
@Deprecated
public MongoDBAASAPIFactory(BaSyxMongoDBConfiguration config) {
- this(config, MongoClients.create(config.getConnectionUrl()));
+ this(MongoDBBaSyxStorageAPIFactory.create(config.getAASCollection(), AssetAdministrationShell.class, config));
}
public MongoDBAASAPIFactory(BaSyxMongoDBConfiguration config, MongoClient client) {
- this.config = config;
- this.client = client;
+ this(MongoDBBaSyxStorageAPIFactory.create(config.getAASCollection(), AssetAdministrationShell.class, config, client));
+ }
+
+ public MongoDBAASAPIFactory(MongoDBBaSyxStorageAPI mongoDBStorageAPI) {
+ this.storageAPI = mongoDBStorageAPI;
}
@Override
- public IAASAPI getAASApi(AssetAdministrationShell aas) {
- MongoDBAASAPI api = new MongoDBAASAPI(config, aas.getIdentification().getId(), client);
- api.setAAS(aas);
+ public IAASAPI getAASApi(AssetAdministrationShell shell) {
+ MongoDBAASAPI api = new MongoDBAASAPI(storageAPI, shell.getIdentification().getId());
+ api.setAAS(shell);
return api;
}
+ @Override
+ public IAASAPI create(IIdentifier aasId) {
+ return new MongoDBAASAPI(storageAPI, aasId.getId());
+ }
+
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAggregator.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAggregator.java
index fbbc7322..5632cc22 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAggregator.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAggregator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2021 the Eclipse BaSyx Authors
+ * Copyright (C) 2021, 2023 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -24,15 +24,9 @@
******************************************************************************/
package org.eclipse.basyx.components.aas.mongodb;
-import static org.springframework.data.mongodb.core.query.Criteria.where;
-import static org.springframework.data.mongodb.core.query.Query.query;
-
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.stream.Collectors;
import org.eclipse.basyx.aas.aggregator.AASAggregator;
@@ -46,7 +40,8 @@
import org.eclipse.basyx.aas.restapi.api.IAASAPIFactory;
import org.eclipse.basyx.components.aas.aascomponent.MongoDBAASServerComponentFactory;
import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
-import org.eclipse.basyx.extensions.shared.authorization.internal.NotAuthorizedException;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPI;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPIFactory;
import org.eclipse.basyx.submodel.aggregator.SubmodelAggregatorFactory;
import org.eclipse.basyx.submodel.aggregator.api.ISubmodelAggregator;
import org.eclipse.basyx.submodel.aggregator.api.ISubmodelAggregatorFactory;
@@ -55,9 +50,6 @@
import org.eclipse.basyx.submodel.metamodel.api.reference.IReference;
import org.eclipse.basyx.submodel.metamodel.api.reference.enums.KeyType;
import org.eclipse.basyx.submodel.metamodel.map.Submodel;
-import org.eclipse.basyx.submodel.metamodel.map.identifier.Identifier;
-import org.eclipse.basyx.submodel.metamodel.map.qualifier.Identifiable;
-import org.eclipse.basyx.submodel.metamodel.map.qualifier.Referable;
import org.eclipse.basyx.submodel.restapi.SubmodelProvider;
import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPI;
import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPIFactory;
@@ -67,9 +59,6 @@
import org.eclipse.basyx.vab.protocol.http.connector.HTTPConnectorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.data.mongodb.core.MongoOperations;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
@@ -79,32 +68,22 @@
*
* @see AASAggregator AASAggregator for the "InMemory"-variant
*
- * @author espen, wege
+ * @author espen, wege, witt, jugnjan, zhangzai
*
*/
public class MongoDBAASAggregator implements IAASAggregator {
- private static Logger logger = LoggerFactory.getLogger(MongoDBAASAggregator.class);
-
- private static final String IDSHORTPATH = Referable.IDSHORT;
- private static final String IDPATH = Identifiable.IDENTIFICATION + "." + Identifier.ID;
-
- protected Map aasProviderMap = new HashMap<>();
- protected BaSyxMongoDBConfiguration config;
- protected MongoOperations mongoOps;
- protected String aasCollection;
- protected String smCollection;
-
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
private IAASRegistry registry;
/**
* Store AAS API Provider. By default, uses the MongoDB API Provider
*/
- protected IAASAPIFactory aasApiProvider;
+ protected IAASAPIFactory shellApiFactory;
/**
* Store Submodel API Provider. By default, uses a MongoDB Submodel Provider
*/
- protected ISubmodelAPIFactory smApiProvider;
+ protected ISubmodelAPIFactory submodelApiFactory;
/**
* Store SubmodelAggregator. By default, uses standard SubmodelAggregator
@@ -115,21 +94,89 @@ public class MongoDBAASAggregator implements IAASAggregator {
protected ISubmodelAggregator submodelAggregator;
protected ISubmodelAggregatorFactory submodelAggregatorFactory;
+ private MongoDBBaSyxStorageAPI submodelStorageApi;
+ private MongoDBBaSyxStorageAPI shellStorageApi;
+
+ public MongoDBAASAggregator(IAASRegistry registry, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoDBBaSyxStorageAPI submodelStorageApi,
+ MongoDBBaSyxStorageAPI shellStorageApi) {
+ this.submodelStorageApi = submodelStorageApi;
+ this.shellStorageApi = shellStorageApi;
+ this.shellApiFactory = shellAPIFactory;
+ this.submodelAggregatorFactory = submodelAggregatorFactory;
+ this.registry = registry;
+ }
+
/**
- * Receives a BaSyxMongoDBConfiguration and a registry to create a persistent
- * MongoDB backend.
- *
+ * Receives a BaSyxMongoDBConfiguration, IAASRegistry, IAASAPIFactory,
+ * ISubmodelAggregatorFactory and a MongoClient to create a persistent MongoDB
+ * backend.
+ *
* @param config
- * The MongoDB Configuration
+ * @param registry
+ * @param shellAPIFactory
+ * @param submodelAggregatorFactory
*
- * @deprecated Use new MongoDBAASAggregator with the
- * {@link MongoDBAASServerComponentFactory}.
*/
- @Deprecated
- public MongoDBAASAggregator(BaSyxMongoDBConfiguration config) {
- this.setConfiguration(config);
- submodelAggregatorFactory = new SubmodelAggregatorFactory(smApiProvider);
- init();
+ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASRegistry registry, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ this(registry, shellAPIFactory, submodelAggregatorFactory, submodelStorageApiFromConfig(config, client), shellStorageApiFromConfig(config, client));
+ }
+
+ /**
+ * Receives a BaSyxMongoDBConfiguration,
+ * IAASAPIFactory,ISubmodelAggregatorFactory and a MongoClient to create a
+ * persistent MongoDB backend.
+ *
+ * @param config
+ * @param shellAPIFactory
+ * @param submodelAggregatorFactory
+ * @param client
+ *
+ */
+ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ this(config, null, shellAPIFactory, submodelAggregatorFactory, client);
+ }
+
+ /**
+ * Receives a resourceConfigPath, IAASRegistry, IAASAPIFactory,
+ * ISubmodelAggregatorFactory and a MongoClient to create a persistent MongoDB
+ * backend.
+ *
+ * @param resourceConfigPath
+ * @param registry
+ * @param shellAPIFactory
+ * @param submodelAggregatorFactory
+ * @param client
+ * Use the new constructor using a MongoClient
+ *
+ */
+ public MongoDBAASAggregator(String resourceConfigPath, IAASRegistry registry, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ this(loadConfigFromPath(resourceConfigPath), registry, shellAPIFactory, submodelAggregatorFactory, client);
+ }
+
+ /**
+ * Receives a resourceConfigPath, IAASAPIFactory, ISubmodelAggregatorFactory and
+ * a MongoClient to create a persistent MongoDB backend.
+ *
+ * @param resourceConfigPath
+ * @param shellAPIFactory
+ * @param submodelAggregatorFactory
+ * @param client
+ *
+ */
+ public MongoDBAASAggregator(String resourceConfigPath, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ this(loadConfigFromPath(resourceConfigPath), shellAPIFactory, submodelAggregatorFactory, client);
+ }
+
+ /**
+ * Constructor using the default configuration, with the given
+ * IAASAPIFactory,ISubmodelAggregatorFactory and MongoClient.
+ *
+ * @param shellAPIFactory
+ * @param submodelAggregatorFactory
+ * @param client
+ */
+ public MongoDBAASAggregator(IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ this(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH, shellAPIFactory, submodelAggregatorFactory, client);
}
/**
@@ -138,18 +185,13 @@ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config) {
*
* @param config
* The MongoDB Configuration
- * @param registry
- * The registry
*
* @deprecated Use new MongoDBAASAggregator with the
* {@link MongoDBAASServerComponentFactory}.
*/
@Deprecated
- public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASRegistry registry) {
- this.setConfiguration(config);
- this.registry = registry;
- submodelAggregatorFactory = new SubmodelAggregatorFactory(smApiProvider);
- init();
+ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config) {
+ this(config, null);
}
/**
@@ -164,11 +206,7 @@ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASRegistry regis
*/
@Deprecated
public MongoDBAASAggregator(String resourceConfigPath) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- this.setConfiguration(config);
- submodelAggregatorFactory = new SubmodelAggregatorFactory(smApiProvider);
- init();
+ this(loadConfigFromPath(resourceConfigPath));
}
/**
@@ -184,12 +222,24 @@ public MongoDBAASAggregator(String resourceConfigPath) {
*/
@Deprecated
public MongoDBAASAggregator(String resourceConfigPath, IAASRegistry registry) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- this.setConfiguration(config);
- submodelAggregatorFactory = new SubmodelAggregatorFactory(smApiProvider);
- this.registry = registry;
- init();
+ this(loadConfigFromPath(resourceConfigPath), registry);
+ }
+
+ /**
+ * Receives a BaSyxMongoDBConfiguration and a registry to create a persistent
+ * MongoDB backend.
+ *
+ * @param config
+ * The MongoDB Configuration
+ * @param registry
+ * The registry
+ *
+ * @deprecated Use new MongoDBAASAggregator with the
+ * {@link MongoDBAASServerComponentFactory}.
+ */
+ @Deprecated
+ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASRegistry registry) {
+ this(registry, initShellApiFactory(config), initSubmodelAggregatorFactory(config), submodelStorageApiFromConfig(config, null), shellStorageApiFromConfig(config, null));
}
/**
@@ -222,33 +272,13 @@ public MongoDBAASAggregator(IAASRegistry registry) {
*
* @param config
* @param registry
- * @param aasAPIFactory
+ * @param shellAPIFactory
* @param submodelAggregatorFactory
* @deprecated Use the new constructor using a MongoClient
*/
@Deprecated
- public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASRegistry registry, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
- this(config, registry, aasAPIFactory, submodelAggregatorFactory, MongoClients.create(config.getConnectionUrl()));
- }
-
- /**
- * Receives a BaSyxMongoDBConfiguration, IAASRegistry, IAASAPIFactory,
- * ISubmodelAggregatorFactory and a MongoClient to create a persistent MongoDB
- * backend.
- *
- * @param config
- * @param registry
- * @param aasAPIFactory
- * @param submodelAggregatorFactory
- *
- */
- public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASRegistry registry, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
- setMongoDBConfiguration(config, client);
- this.config = config;
- this.registry = registry;
- this.aasApiProvider = aasAPIFactory;
- this.submodelAggregatorFactory = submodelAggregatorFactory;
- init();
+ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASRegistry registry, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ this(config, registry, shellAPIFactory, submodelAggregatorFactory, MongoClients.create(config.getConnectionUrl()));
}
/**
@@ -256,32 +286,13 @@ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASRegistry regis
* ISubmodelAggregatorFactory to create a persistent MongoDB backend.
*
* @param config
- * @param aasAPIFactory
+ * @param shellAPIFactory
* @param submodelAggregatorFactory
* @deprecated Use the new constructor using a MongoClient
*/
@Deprecated
- public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
- this(config, aasAPIFactory, submodelAggregatorFactory, MongoClients.create(config.getConnectionUrl()));
- }
-
- /**
- * Receives a BaSyxMongoDBConfiguration,
- * IAASAPIFactory,ISubmodelAggregatorFactory and a MongoClient to create a
- * persistent MongoDB backend.
- *
- * @param config
- * @param aasAPIFactory
- * @param submodelAggregatorFactory
- * @param client
- *
- */
- public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
- setMongoDBConfiguration(config, client);
- this.config = config;
- this.aasApiProvider = aasAPIFactory;
- this.submodelAggregatorFactory = submodelAggregatorFactory;
- init();
+ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ this(config, shellAPIFactory, submodelAggregatorFactory, MongoClients.create(config.getConnectionUrl()));
}
/**
@@ -290,42 +301,13 @@ public MongoDBAASAggregator(BaSyxMongoDBConfiguration config, IAASAPIFactory aas
*
* @param resourceConfigPath
* @param registry
- * @param aasAPIFactory
+ * @param shellAPIFactory
* @param submodelAggregatorFactory
* @deprecated Use the new constructor using a MongoClient
*/
@Deprecated
- public MongoDBAASAggregator(String resourceConfigPath, IAASRegistry registry, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- setMongoDBConfiguration(config, MongoClients.create(config.getConnectionUrl()));
- this.registry = registry;
- this.aasApiProvider = aasAPIFactory;
- this.submodelAggregatorFactory = submodelAggregatorFactory;
- init();
- }
-
- /**
- * Receives a resourceConfigPath, IAASRegistry, IAASAPIFactory,
- * ISubmodelAggregatorFactory and a MongoClient to create a persistent MongoDB
- * backend.
- *
- * @param resourceConfigPath
- * @param registry
- * @param aasAPIFactory
- * @param submodelAggregatorFactory
- * @param client
- * Use the new constructor using a MongoClient
- *
- */
- public MongoDBAASAggregator(String resourceConfigPath, IAASRegistry registry, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- setMongoDBConfiguration(config, client);
- this.registry = registry;
- this.aasApiProvider = aasAPIFactory;
- this.submodelAggregatorFactory = submodelAggregatorFactory;
- init();
+ public MongoDBAASAggregator(String resourceConfigPath, IAASRegistry registry, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ this(loadConfigFromPath(resourceConfigPath), registry, shellAPIFactory, submodelAggregatorFactory);
}
/**
@@ -333,62 +315,61 @@ public MongoDBAASAggregator(String resourceConfigPath, IAASRegistry registry, IA
* ISubmodelAggregatorFactory to create a persistent MongoDB backend.
*
* @param resourceConfigPath
- * @param aasAPIFactory
+ * @param shellAPIFactory
* @param submodelAggregatorFactory
* @deprecated Use the new constructor using a MongoClient
*/
@Deprecated
- public MongoDBAASAggregator(String resourceConfigPath, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- setMongoDBConfiguration(config, MongoClients.create(config.getConnectionUrl()));
- this.aasApiProvider = aasAPIFactory;
- this.submodelAggregatorFactory = submodelAggregatorFactory;
- init();
- }
-
- /**
- * Receives a resourceConfigPath, IAASAPIFactory, ISubmodelAggregatorFactory and
- * a MongoClient to create a persistent MongoDB backend.
- *
- * @param resourceConfigPath
- * @param aasAPIFactory
- * @param submodelAggregatorFactory
- * @param client
- *
- */
- public MongoDBAASAggregator(String resourceConfigPath, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- setMongoDBConfiguration(config, client);
- this.aasApiProvider = aasAPIFactory;
- this.submodelAggregatorFactory = submodelAggregatorFactory;
- init();
+ public MongoDBAASAggregator(String resourceConfigPath, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ this(loadConfigFromPath(resourceConfigPath), shellAPIFactory, submodelAggregatorFactory);
}
/**
* Constructor using the default configuration, with the given IAASAPIFactory
* and ISubmodelAggregatorFactory.
*
- * @param aasAPIFactory
+ * @param shellAPIFactory
* @param submodelAggregatorFactory
* @deprecated Use the new constructor using a MongoClient
*/
@Deprecated
- public MongoDBAASAggregator(IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
- this(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH, aasAPIFactory, submodelAggregatorFactory);
+ public MongoDBAASAggregator(IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ this(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH, shellAPIFactory, submodelAggregatorFactory);
}
- /**
- * Constructor using the default configuration, with the given
- * IAASAPIFactory,ISubmodelAggregatorFactory and MongoClient.
- *
- * @param aasAPIFactory
- * @param submodelAggregatorFactory
- * @param client
- */
- public MongoDBAASAggregator(IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
- this(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH, aasAPIFactory, submodelAggregatorFactory, client);
+ private static ISubmodelAggregatorFactory initSubmodelAggregatorFactory(BaSyxMongoDBConfiguration config) {
+ ISubmodelAPIFactory submodelApiFactory = initSubmodelApiFactory(config);
+ return new SubmodelAggregatorFactory(submodelApiFactory);
+ }
+
+ @SuppressWarnings("deprecation")
+ private static ISubmodelAPIFactory initSubmodelApiFactory(BaSyxMongoDBConfiguration config) {
+ return new MongoDBSubmodelAPIFactory(config);
+ }
+
+ @SuppressWarnings("deprecation")
+ private static IAASAPIFactory initShellApiFactory(BaSyxMongoDBConfiguration config) {
+ return new MongoDBAASAPIFactory(config);
+ }
+
+ private static MongoDBBaSyxStorageAPI submodelStorageApiFromConfig(BaSyxMongoDBConfiguration config, MongoClient client) {
+ String submodelCollectionName = config.getSubmodelCollection();
+ MongoDBBaSyxStorageAPI submodelStorageApi = client == null ? MongoDBBaSyxStorageAPIFactory.create(submodelCollectionName, Submodel.class, config)
+ : MongoDBBaSyxStorageAPIFactory.create(submodelCollectionName, Submodel.class, config, client);
+ return submodelStorageApi;
+ }
+
+ private static MongoDBBaSyxStorageAPI shellStorageApiFromConfig(BaSyxMongoDBConfiguration config, MongoClient client) {
+ String shellCollectionName = config.getAASCollection();
+ MongoDBBaSyxStorageAPI shellStorageApi = client == null ? MongoDBBaSyxStorageAPIFactory.create(shellCollectionName, AssetAdministrationShell.class, config)
+ : MongoDBBaSyxStorageAPIFactory.create(shellCollectionName, AssetAdministrationShell.class, config, client);
+ return shellStorageApi;
+ }
+
+ private static BaSyxMongoDBConfiguration loadConfigFromPath(String resourceConfigPath) {
+ BaSyxMongoDBConfiguration config = new BaSyxMongoDBConfiguration();
+ config.loadFromResource(resourceConfigPath);
+ return config;
}
/**
@@ -408,203 +389,146 @@ public void setRegistry(IAASRegistry registry) {
this.registry = registry;
}
- /**
- * Sets the db configuration for this Aggregator.
- *
- * @param config
- * The MongoDB Configuration
- *
- * @deprecated This method is used with the old, deprecated Constructors. Use
- * {@link MongoDBAASServerComponentFactory} instead
- */
- @SuppressWarnings("deprecation")
- @Deprecated
- public void setConfiguration(BaSyxMongoDBConfiguration config) {
- // set mongoDB configuration
- this.config = config;
- MongoClient client = MongoClients.create(config.getConnectionUrl());
- this.mongoOps = new MongoTemplate(client, config.getDatabase());
- this.aasCollection = config.getAASCollection();
- this.smCollection = config.getSubmodelCollection();
-
- // Create API factories with the given configuration
- this.aasApiProvider = aas -> {
- MongoDBAASAPI api = new MongoDBAASAPI(config, aas.getIdentification().getId());
- api.setAAS(aas);
- return api;
- };
- this.smApiProvider = sm -> {
- MongoDBSubmodelAPI api = new MongoDBSubmodelAPI(config, sm.getIdentification().getId());
- api.setSubmodel(sm);
- return api;
- };
- }
-
- private void setMongoDBConfiguration(BaSyxMongoDBConfiguration config, MongoClient client) {
- this.config = config;
- this.mongoOps = new MongoTemplate(client, config.getDatabase());
- this.aasCollection = config.getAASCollection();
- this.smCollection = config.getSubmodelCollection();
- }
-
/**
* Removes all persistent AAS and submodels
*/
public void reset() {
- mongoOps.dropCollection(aasCollection);
- mongoOps.dropCollection(smCollection);
- aasProviderMap.clear();
- }
-
- @SuppressWarnings("deprecation")
- private void init() {
- List data = mongoOps.findAll(AssetAdministrationShell.class, aasCollection);
- for (AssetAdministrationShell aas : data) {
- String aasId = aas.getIdentification().getId();
- logger.info("Adding AAS from DB: " + aasId);
- MongoDBAASAPI aasApi = new MongoDBAASAPI(config, aasId);
- MultiSubmodelProvider provider = createMultiSubmodelProvider(aasApi);
- addSubmodelsFromDB(provider, aas);
- aasProviderMap.put(aas.getIdentification().getId(), provider);
- }
+ Collection shells = shellStorageApi.retrieveAll();
+ Collection submodels = submodelStorageApi.retrieveAll();
+ shells.forEach(shell -> shellStorageApi.delete(shell.getIdentification().getId()));
+ submodels.forEach(shell -> submodelStorageApi.delete(shell.getIdentification().getId()));
}
/**
* Initializes and returns a VABMultiSubmodelProvider with only the
* AssetAdministrationShell
*/
- private MultiSubmodelProvider createMultiSubmodelProvider(IAASAPI aasApi) {
- AASModelProvider aasProvider = new AASModelProvider(aasApi);
- IConnectorFactory connProvider = new HTTPConnectorFactory();
+ private MultiSubmodelProvider createMultiSubmodelProvider(IAASAPI shellApi) {
+ AASModelProvider contentProvider = createContentProvider(shellApi);
+ IConnectorFactory connectorFactory = new HTTPConnectorFactory();
- ISubmodelAggregator usedAggregator = getSubmodelAggregatorInstance();
+ ISubmodelAggregator submodelAggregator = getSubmodelAggregatorInstance(shellApi.getAAS().getIdentification());
- return new MultiSubmodelProvider(aasProvider, registry, connProvider, aasApiProvider, usedAggregator);
+ return new MultiSubmodelProvider(contentProvider, this.registry, connectorFactory, this.shellApiFactory, submodelAggregator);
}
- private ISubmodelAggregator getSubmodelAggregatorInstance() {
+ private AASModelProvider createContentProvider(IAASAPI shellApi) {
+ return new AASModelProvider(shellApi);
+ }
+
+ private ISubmodelAggregator getSubmodelAggregatorInstance(IIdentifier shellId) {
if (submodelAggregatorFactory == null) {
return submodelAggregator;
}
- return submodelAggregatorFactory.create();
+ return submodelAggregatorFactory.create(shellId);
}
/**
* Adds submodel providers for submodels in the MongoDB
*/
- private void addSubmodelsFromDB(MultiSubmodelProvider provider, AssetAdministrationShell aas) {
- // Get ids and idShorts from aas
- Collection submodelRefs = aas.getSubmodelReferences();
- List smIds = new ArrayList<>();
- List smIdShorts = new ArrayList<>();
- for (IReference ref : submodelRefs) {
- List keys = ref.getKeys();
- IKey lastKey = keys.get(keys.size() - 1);
- if (lastKey.getIdType() == KeyType.IDSHORT) {
- smIdShorts.add(lastKey.getValue());
- } else {
- smIds.add(lastKey.getValue());
- }
- }
+ private void addSubmodelsFromDB(MultiSubmodelProvider provider, AssetAdministrationShell shell) {
+ Collection submodelRefs = shell.getSubmodelReferences();
+ List submodelIdentificationIds = getSubmodelIdentificationIdsFromSubmodelReferences(submodelRefs);
+ List submodelIdShorts = getSubmodelIdShortsFromSubmodelReferences(submodelRefs);
+ submodelIdentificationIds = completeSubmodelIdentificationsIdsByIdShorts(submodelIdentificationIds, submodelIdShorts);
+
+ createProviderForSubmodels(provider, submodelIdentificationIds);
+
+ }
- // Add submodel ids by id shorts
- for (String idShort : smIdShorts) {
- String id = getSubmodelId(idShort);
+ private void createProviderForSubmodels(MultiSubmodelProvider provider, List submodelIdentificationIds) {
+ submodelIdentificationIds.forEach(submodelIdentificationId -> addSubmodelProvidersById(submodelIdentificationId, provider));
+ }
+
+ private List completeSubmodelIdentificationsIdsByIdShorts(List submodelIdentificationIds, List submodelIdShorts) {
+ submodelIdShorts.forEach(idShort -> {
+ String id = getSubmodelIdByIdShort(idShort);
if (id != null) {
- smIds.add(id);
+ submodelIdentificationIds.add(id);
}
- }
+ });
+ return submodelIdentificationIds;
+ }
- // Create a provider for each submodel
- for (String id : smIds) {
- logger.info("Adding Submodel from DB: " + id);
- addSubmodelProvidersById(id, provider);
- }
+ private List getSubmodelIdentificationIdsFromSubmodelReferences(Collection submodelRefs) {
+ List submodelIdentificationIds = submodelRefs.stream().map(this::getLastKeyFromReference).filter(lastKey -> lastKey.getIdType() != KeyType.IDSHORT).map(lastKey -> lastKey.getValue()).collect(Collectors.toList());
+ return submodelIdentificationIds;
+ }
+
+ private List getSubmodelIdShortsFromSubmodelReferences(Collection submodelRefs) {
+ List submodelIdShorts = submodelRefs.stream().map(this::getLastKeyFromReference).filter(lastKey -> lastKey.getIdType() == KeyType.IDSHORT).map(lastKey -> lastKey.getValue()).collect(Collectors.toList());
+ return submodelIdShorts;
}
- private String getSubmodelId(String idShort) {
- Submodel sm = mongoOps.findOne(query(where(IDSHORTPATH).is(idShort)), Submodel.class);
- if (sm != null) {
- return sm.getIdentification().getId();
+ private IKey getLastKeyFromReference(IReference reference) {
+ List keys = reference.getKeys();
+ IKey lastKey = keys.get(keys.size() - 1);
+ return lastKey;
+ }
+
+ private String getSubmodelIdByIdShort(String idShort) {
+ Submodel submodel = submodelStorageApi.retrieve(idShort);
+ if (submodel != null) {
+ return submodel.getIdentification().getId();
}
return null;
}
- @SuppressWarnings("deprecation")
- private void addSubmodelProvidersById(String smId, MultiSubmodelProvider provider) {
- ISubmodelAPI smApi = new MongoDBSubmodelAPI(config, smId);
- SubmodelProvider smProvider = new SubmodelProvider(smApi);
- provider.addSubmodel(smProvider);
+ private void addSubmodelProvidersById(String submodelIdentificationId, MultiSubmodelProvider provider) {
+ ISubmodelAPI submodelApi = new MongoDBSubmodelAPI(this.submodelStorageApi, submodelIdentificationId);
+ try {
+ SubmodelProvider submodelProvider = new SubmodelProvider(submodelApi);
+ provider.addSubmodel(submodelProvider);
+ } catch (ResourceNotFoundException noSubmodelsInDB) {
+ // ignore
+ logger.warn("Could not add submodel with identificationId '{}'.", submodelIdentificationId);
+ }
+
}
- @SuppressWarnings("unchecked")
@Override
public Collection getAASList() {
- return aasProviderMap.values().stream().map(p -> {
- try {
- return p.getValue("/aas");
- } catch (NotAuthorizedException e) {
- return null;
- } catch (Exception e1) {
- e1.printStackTrace();
- throw new RuntimeException();
- }
- }).filter(Objects::nonNull).map(m -> {
- AssetAdministrationShell aas = new AssetAdministrationShell();
- aas.putAll((Map extends String, ? extends Object>) m);
- return aas;
- }).collect(Collectors.toList());
+ return shellStorageApi.retrieveAll().stream().map(aas -> (IAssetAdministrationShell) aas).collect(Collectors.toList());
}
@SuppressWarnings("unchecked")
@Override
- public IAssetAdministrationShell getAAS(IIdentifier aasId) {
- IModelProvider aasProvider = getAASProvider(aasId);
+ public IAssetAdministrationShell getAAS(IIdentifier shellIdentification) {
+ IModelProvider shellProvider = getAASProvider(shellIdentification);
- // get all Elements from provider
- Map aasMap = (Map) aasProvider.getValue("/aas");
- return AssetAdministrationShell.createAsFacade(aasMap);
+ Map shellMap = (Map) shellProvider.getValue("/aas");
+ return AssetAdministrationShell.createAsFacade(shellMap);
}
@Override
- public void createAAS(AssetAdministrationShell aas) {
- IAASAPI aasApi = this.aasApiProvider.create(aas);
- MultiSubmodelProvider provider = createMultiSubmodelProvider(aasApi);
- aasProviderMap.put(aas.getIdentification().getId(), provider);
+ public void createAAS(AssetAdministrationShell shell) {
+ this.shellApiFactory.create(shell);
}
@Override
- public void updateAAS(AssetAdministrationShell aas) {
- MultiSubmodelProvider oldProvider = (MultiSubmodelProvider) getAASProvider(aas.getIdentification());
- IAASAPI aasApi = aasApiProvider.create(aas);
- AASModelProvider contentProvider = new AASModelProvider(aasApi);
- IConnectorFactory connectorFactory = oldProvider.getConnectorFactory();
-
- MultiSubmodelProvider updatedProvider = new MultiSubmodelProvider(contentProvider, registry, connectorFactory, aasApiProvider, oldProvider.getSmAggregator());
-
- aasProviderMap.put(aas.getIdentification().getId(), updatedProvider);
+ public void updateAAS(AssetAdministrationShell shell) {
+ this.shellApiFactory.create(shell);
}
@Override
- public void deleteAAS(IIdentifier aasId) {
- Query hasId = query(where(IDPATH).is(aasId.getId()));
- mongoOps.remove(hasId, aasCollection);
- aasProviderMap.remove(aasId.getId());
+ public void deleteAAS(IIdentifier shellIdentifier) {
+ String shellIdentificationId = shellIdentifier.getId();
+ shellStorageApi.delete(shellIdentificationId);
}
- public MultiSubmodelProvider getProviderForAASId(String aasId) {
- return aasProviderMap.get(aasId);
- }
+ public MultiSubmodelProvider getProviderForAASId(String shellIdentificationId) {
+ AssetAdministrationShell shell = shellStorageApi.retrieve(shellIdentificationId);
- @Override
- public IModelProvider getAASProvider(IIdentifier aasId) {
- MultiSubmodelProvider provider = aasProviderMap.get(aasId.getId());
-
- if (provider == null) {
- throw new ResourceNotFoundException("AAS with Id " + aasId.getId() + " does not exist");
- }
+ IAASAPI shellApi = this.shellApiFactory.create(shell.getIdentification());
+ MultiSubmodelProvider provider = createMultiSubmodelProvider(shellApi);
+ addSubmodelsFromDB(provider, shell);
return provider;
}
+
+ @Override
+ public IModelProvider getAASProvider(IIdentifier shellIdentificationId) {
+ return getProviderForAASId(shellIdentificationId.getId());
+ }
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAggregatorFactory.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAggregatorFactory.java
index 2128129e..29e4712e 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAggregatorFactory.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBAASAggregatorFactory.java
@@ -45,87 +45,87 @@ public class MongoDBAASAggregatorFactory implements IAASAggregatorFactory {
private BaSyxMongoDBConfiguration config;
private IAASRegistry registry;
- private IAASAPIFactory aasAPIFactory;
+ private IAASAPIFactory shellAPIFactory;
private ISubmodelAggregatorFactory submodelAggregatorFactory;
private String resourceConfigPath;
private MongoClient client;
@Deprecated
- public MongoDBAASAggregatorFactory(BaSyxMongoDBConfiguration config, IAASRegistry registry, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
- this(config, registry, aasAPIFactory, submodelAggregatorFactory, MongoClients.create(config.getConnectionUrl()));
+ public MongoDBAASAggregatorFactory(BaSyxMongoDBConfiguration config, IAASRegistry registry, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ this(config, registry, shellAPIFactory, submodelAggregatorFactory, MongoClients.create(config.getConnectionUrl()));
}
@Deprecated
- public MongoDBAASAggregatorFactory(BaSyxMongoDBConfiguration config, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
- this(config, aasAPIFactory, submodelAggregatorFactory, MongoClients.create(config.getConnectionUrl()));
+ public MongoDBAASAggregatorFactory(BaSyxMongoDBConfiguration config, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ this(config, shellAPIFactory, submodelAggregatorFactory, MongoClients.create(config.getConnectionUrl()));
}
@Deprecated
- public MongoDBAASAggregatorFactory(String resourceConfigPath, IAASRegistry registry, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ public MongoDBAASAggregatorFactory(String resourceConfigPath, IAASRegistry registry, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
this.resourceConfigPath = resourceConfigPath;
this.registry = registry;
- this.aasAPIFactory = aasAPIFactory;
+ this.shellAPIFactory = shellAPIFactory;
this.submodelAggregatorFactory = submodelAggregatorFactory;
this.client = MongoClients.create(config.getConnectionUrl());
}
@Deprecated
- public MongoDBAASAggregatorFactory(String resourceConfigPath, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ public MongoDBAASAggregatorFactory(String resourceConfigPath, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
this.resourceConfigPath = resourceConfigPath;
- this.aasAPIFactory = aasAPIFactory;
+ this.shellAPIFactory = shellAPIFactory;
this.submodelAggregatorFactory = submodelAggregatorFactory;
this.client = MongoClients.create(config.getConnectionUrl());
}
@Deprecated
- public MongoDBAASAggregatorFactory(IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
- this(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH, aasAPIFactory, submodelAggregatorFactory);
+ public MongoDBAASAggregatorFactory(IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory) {
+ this(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH, shellAPIFactory, submodelAggregatorFactory);
}
- public MongoDBAASAggregatorFactory(BaSyxMongoDBConfiguration config, IAASRegistry registry, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ public MongoDBAASAggregatorFactory(BaSyxMongoDBConfiguration config, IAASRegistry registry, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
this.config = config;
this.registry = registry;
- this.aasAPIFactory = aasAPIFactory;
+ this.shellAPIFactory = shellAPIFactory;
this.submodelAggregatorFactory = submodelAggregatorFactory;
this.client = client;
}
- public MongoDBAASAggregatorFactory(BaSyxMongoDBConfiguration config, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ public MongoDBAASAggregatorFactory(BaSyxMongoDBConfiguration config, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
this.config = config;
- this.aasAPIFactory = aasAPIFactory;
+ this.shellAPIFactory = shellAPIFactory;
this.submodelAggregatorFactory = submodelAggregatorFactory;
this.client = client;
}
- public MongoDBAASAggregatorFactory(String resourceConfigPath, IAASRegistry registry, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ public MongoDBAASAggregatorFactory(String resourceConfigPath, IAASRegistry registry, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
this.resourceConfigPath = resourceConfigPath;
this.registry = registry;
- this.aasAPIFactory = aasAPIFactory;
+ this.shellAPIFactory = shellAPIFactory;
this.submodelAggregatorFactory = submodelAggregatorFactory;
this.client = client;
}
- public MongoDBAASAggregatorFactory(String resourceConfigPath, IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ public MongoDBAASAggregatorFactory(String resourceConfigPath, IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
this.resourceConfigPath = resourceConfigPath;
- this.aasAPIFactory = aasAPIFactory;
+ this.shellAPIFactory = shellAPIFactory;
this.submodelAggregatorFactory = submodelAggregatorFactory;
this.client = client;
}
- public MongoDBAASAggregatorFactory(IAASAPIFactory aasAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
- this(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH, aasAPIFactory, submodelAggregatorFactory);
+ public MongoDBAASAggregatorFactory(IAASAPIFactory shellAPIFactory, ISubmodelAggregatorFactory submodelAggregatorFactory, MongoClient client) {
+ this(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH, shellAPIFactory, submodelAggregatorFactory);
}
@Override
public IAASAggregator create() {
if (this.config != null && this.registry != null) {
- return new MongoDBAASAggregator(this.config, this.registry, this.aasAPIFactory, this.submodelAggregatorFactory, this.client);
+ return new MongoDBAASAggregator(this.config, this.registry, this.shellAPIFactory, this.submodelAggregatorFactory, this.client);
} else if (this.config != null) {
- return new MongoDBAASAggregator(this.config, this.aasAPIFactory, this.submodelAggregatorFactory, this.client);
+ return new MongoDBAASAggregator(this.config, this.shellAPIFactory, this.submodelAggregatorFactory, this.client);
} else if (this.resourceConfigPath != null && this.registry != null) {
- return new MongoDBAASAggregator(this.resourceConfigPath, this.registry, this.aasAPIFactory, this.submodelAggregatorFactory, this.client);
+ return new MongoDBAASAggregator(this.resourceConfigPath, this.registry, this.shellAPIFactory, this.submodelAggregatorFactory, this.client);
} else {
- return new MongoDBAASAggregator(this.resourceConfigPath, this.aasAPIFactory, this.submodelAggregatorFactory, this.client);
+ return new MongoDBAASAggregator(this.resourceConfigPath, this.shellAPIFactory, this.submodelAggregatorFactory, this.client);
}
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAPI.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAPI.java
index c02cf109..b87e069d 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAPI.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAPI.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2021 the Eclipse BaSyx Authors
+ * Copyright (C) 2021, 2023 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -24,564 +24,158 @@
******************************************************************************/
package org.eclipse.basyx.components.aas.mongodb;
-import static org.springframework.data.mongodb.core.query.Criteria.where;
-import static org.springframework.data.mongodb.core.query.Query.query;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.apache.tika.mime.MimeType;
-import org.apache.tika.mime.MimeTypeException;
-import org.apache.tika.mime.MimeTypes;
+import org.eclipse.basyx.components.aas.internal.StorageSubmodelAPI;
import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
-import org.eclipse.basyx.submodel.metamodel.api.ISubmodel;
-import org.eclipse.basyx.submodel.metamodel.api.submodelelement.ISubmodelElement;
-import org.eclipse.basyx.submodel.metamodel.api.submodelelement.operation.IOperation;
-import org.eclipse.basyx.submodel.metamodel.facade.submodelelement.SubmodelElementFacadeFactory;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPIFactory;
+import org.eclipse.basyx.extensions.internal.storage.BaSyxStorageAPI;
import org.eclipse.basyx.submodel.metamodel.map.Submodel;
import org.eclipse.basyx.submodel.metamodel.map.identifier.Identifier;
import org.eclipse.basyx.submodel.metamodel.map.qualifier.Identifiable;
-import org.eclipse.basyx.submodel.metamodel.map.submodelelement.SubmodelElement;
-import org.eclipse.basyx.submodel.metamodel.map.submodelelement.SubmodelElementCollection;
-import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.File;
-import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.Property;
-import org.eclipse.basyx.submodel.metamodel.map.submodelelement.operation.Operation;
-import org.eclipse.basyx.submodel.restapi.SubmodelElementProvider;
-import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPI;
import org.eclipse.basyx.submodel.restapi.operation.DelegatedInvocationManager;
-import org.eclipse.basyx.vab.exception.provider.MalformedRequestException;
-import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
-import org.eclipse.basyx.vab.modelprovider.VABPathTools;
-import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
-import org.eclipse.basyx.vab.modelprovider.lambda.VABLambdaProvider;
-import org.eclipse.basyx.vab.modelprovider.map.VABMapProvider;
import org.eclipse.basyx.vab.protocol.http.connector.HTTPConnectorFactory;
-import org.springframework.data.mongodb.core.MongoOperations;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
-import com.mongodb.client.MongoDatabase;
-import com.mongodb.client.gridfs.GridFSBucket;
-import com.mongodb.client.gridfs.GridFSBuckets;
-import com.mongodb.client.model.Filters;
/**
* Implements the ISubmodelAPI for a mongoDB backend.
*
- * @author espen
+ * @author fischer
*/
-public class MongoDBSubmodelAPI implements ISubmodelAPI {
+public class MongoDBSubmodelAPI extends StorageSubmodelAPI {
private static final String DEFAULT_CONFIG_PATH = "mongodb.properties";
public static final String SMIDPATH = Identifiable.IDENTIFICATION + "." + Identifier.ID;
protected DelegatedInvocationManager invocationHelper;
protected BaSyxMongoDBConfiguration config;
- protected MongoOperations mongoOps;
protected String collection;
- protected String smId;
- private MongoClient client;
+
/**
* Receives the path of the configuration.properties file in its constructor.
*
* @param config
- * @deprecated Use the new constructor using a MongoClient
*/
- @Deprecated
- public MongoDBSubmodelAPI(BaSyxMongoDBConfiguration config, String smId) {
- this(config, smId, new DelegatedInvocationManager(new HTTPConnectorFactory()));
+ public MongoDBSubmodelAPI(BaSyxMongoDBConfiguration config, String submdoelIdentificationId, MongoClient client) {
+ this(config, submdoelIdentificationId, new DelegatedInvocationManager(new HTTPConnectorFactory()), client);
}
/**
- * Receives the path of the configuration.properties file in its constructor.
- *
- * @param config
+ * Constructor using default MongoDB connections
*/
- public MongoDBSubmodelAPI(BaSyxMongoDBConfiguration config, String smId, MongoClient client) {
- this(config, smId, new DelegatedInvocationManager(new HTTPConnectorFactory()), client);
+ public MongoDBSubmodelAPI(String submodelIdentificationId, MongoClient client) {
+ this(DEFAULT_CONFIG_PATH, submodelIdentificationId, client);
}
- @Deprecated
- public MongoDBSubmodelAPI(BaSyxMongoDBConfiguration config, String smId,
- DelegatedInvocationManager invocationHelper) {
- this(config, smId, invocationHelper, MongoClients.create(config.getConnectionUrl()));
+ public MongoDBSubmodelAPI(String submodelIdentificationId, DelegatedInvocationManager invocationHelper, MongoClient client) {
+ this(DEFAULT_CONFIG_PATH, submodelIdentificationId, invocationHelper, client);
}
- public MongoDBSubmodelAPI(BaSyxMongoDBConfiguration config, String smId,
- DelegatedInvocationManager invocationHelper, MongoClient client) {
- this.client = client;
+ // NEUER KONSTRUKTOR?
+ public MongoDBSubmodelAPI(BaSyxStorageAPI storageAPI, String identificationId, BaSyxMongoDBConfiguration config) {
+ super(storageAPI, identificationId, new DelegatedInvocationManager(new HTTPConnectorFactory()));
this.setConfiguration(config);
- this.setSubmodelId(smId);
- this.invocationHelper = invocationHelper;
}
- /**
- * Receives the path of the .properties file in its constructor from a resource.
- *
- * @deprecated Use the new constructor using a MongoClient
- */
- @Deprecated
- public MongoDBSubmodelAPI(String resourceConfigPath, String smId) {
- this(resourceConfigPath, smId, new DelegatedInvocationManager(new HTTPConnectorFactory()));
+ public MongoDBSubmodelAPI(BaSyxStorageAPI storageAPI, String identificationId) {
+ super(storageAPI, identificationId, new DelegatedInvocationManager(new HTTPConnectorFactory()));
}
/**
* Receives the path of the .properties file in its constructor from a resource.
*/
- public MongoDBSubmodelAPI(String resourceConfigPath, String smId, MongoClient client) {
- this(resourceConfigPath, smId, new DelegatedInvocationManager(new HTTPConnectorFactory()), client);
+ public MongoDBSubmodelAPI(String resourceConfigPath, String submodelIdentificationId, MongoClient client) {
+ this(resourceConfigPath, submodelIdentificationId, new DelegatedInvocationManager(new HTTPConnectorFactory()), client);
}
- @Deprecated
- public MongoDBSubmodelAPI(String resourceConfigPath, String smId, DelegatedInvocationManager invocationHelper) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- this.client = MongoClients.create(config.getConnectionUrl());
+ public MongoDBSubmodelAPI(BaSyxMongoDBConfiguration config, String submodelIdentificationId, DelegatedInvocationManager invocationHelper, MongoClient client) {
+ super(createSubmodelStorageAPI(config, client), submodelIdentificationId, invocationHelper);
this.setConfiguration(config);
- this.setSubmodelId(smId);
+ this.setSubmodelId(submodelIdentificationId);
this.invocationHelper = invocationHelper;
}
- public MongoDBSubmodelAPI(String resourceConfigPath, String smId, DelegatedInvocationManager invocationHelper,
- MongoClient client) {
- config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(resourceConfigPath);
- this.client = client;
+ public MongoDBSubmodelAPI(String resourceConfigPath, String submodelIdentificationId, DelegatedInvocationManager invocationHelper, MongoClient client) {
+ super(createSubmodelStorageAPI(createConfig(resourceConfigPath), client), submodelIdentificationId, invocationHelper);
+ this.config = createConfig(resourceConfigPath);
this.setConfiguration(config);
- this.setSubmodelId(smId);
+ this.setSubmodelId(submodelIdentificationId);
this.invocationHelper = invocationHelper;
}
/**
- * Constructor using default MongoDB connections
+ * Receives the path of the configuration.properties file in its constructor.
*
+ * @param config
* @deprecated Use the new constructor using a MongoClient
*/
@Deprecated
- public MongoDBSubmodelAPI(String smId) {
- this(DEFAULT_CONFIG_PATH, smId);
+ public MongoDBSubmodelAPI(BaSyxMongoDBConfiguration config, String submodelIdentificationId) {
+ this(config, submodelIdentificationId, new DelegatedInvocationManager(new HTTPConnectorFactory()));
}
@Deprecated
- public MongoDBSubmodelAPI(String smId, DelegatedInvocationManager invocationHelper) {
- this(DEFAULT_CONFIG_PATH, smId, invocationHelper);
- }
-
- /**
- * Constructor using default MongoDB connections
- */
- public MongoDBSubmodelAPI(String smId, MongoClient client) {
- this(DEFAULT_CONFIG_PATH, smId, client);
- }
-
- public MongoDBSubmodelAPI(String smId, DelegatedInvocationManager invocationHelper, MongoClient client) {
- this(DEFAULT_CONFIG_PATH, smId, invocationHelper, client);
+ public MongoDBSubmodelAPI(BaSyxMongoDBConfiguration config, String submodelIdentificationId, DelegatedInvocationManager invocationHelper) {
+ this(config, submodelIdentificationId, invocationHelper, MongoClients.create(config.getConnectionUrl()));
}
/**
- * Sets the db configuration for the submodel API.
- *
- * @param config
- */
- public void setConfiguration(BaSyxMongoDBConfiguration config) {
- this.config = config;
- this.mongoOps = new MongoTemplate(client, config.getDatabase());
- this.collection = config.getSubmodelCollection();
- }
-
- /**
- * Sets the submodel id, so that this API points to the submodel with smId. Can
- * be changed to point to a different submodel in the database.
+ * Receives the path of the .properties file in its constructor from a resource.
*
- * @param smId
+ * @deprecated Use the new constructor using a MongoClient
*/
- public void setSubmodelId(String smId) {
- this.smId = smId;
+ @Deprecated
+ public MongoDBSubmodelAPI(String resourceConfigPath, String submodelIdentificationId) {
+ this(resourceConfigPath, submodelIdentificationId, new DelegatedInvocationManager(new HTTPConnectorFactory()));
}
/**
- * Depending on whether the model is already in the db, this method inserts or
- * replaces the existing data. The new submodel id for this API is taken from
- * the given submodel.
+ * Constructor using default MongoDB connections
*
- * @param sm
+ * @deprecated Use the new constructor using a MongoClient
*/
- public void setSubmodel(Submodel sm) {
- String id = sm.getIdentification().getId();
- this.setSubmodelId(id);
-
- Submodel replaced = writeSubmodelInDB(sm);
- if (replaced == null) {
- mongoOps.insert(sm, collection);
- }
- // Remove mongoDB-specific map attribute from SM
- // mongoOps modify sm on save - thus _id has to be removed here...
- sm.remove("_id");
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public ISubmodel getSubmodel() {
- // Query Submodel from MongoDB
- Query hasId = query(where(SMIDPATH).is(smId));
- Submodel result = mongoOps.findOne(hasId, Submodel.class, collection);
- if (result == null) {
- throw new ResourceNotFoundException("The submodel " + smId + " could not be found in the database.");
- }
-
- // Remove mongoDB-specific map attribute from AASDescriptor
- result.remove("_id");
-
- // Cast all SubmodelElement maps to ISubmodelElements before returning the
- // submodel
- Map elements = new HashMap<>();
- Map> elemMaps = (Map>) result
- .get(Submodel.SUBMODELELEMENT);
- for (Entry> entry : elemMaps.entrySet()) {
- String shortId = entry.getKey();
- Map elemMap = entry.getValue();
- ISubmodelElement element = SubmodelElementFacadeFactory.createSubmodelElement(elemMap);
- elements.put(shortId, element);
- }
- // Replace the element map in the submodel
- result.put(Submodel.SUBMODELELEMENT, elements);
- // Return the "fixed" submodel
- return result;
- }
-
- @Override
- public void addSubmodelElement(ISubmodelElement elem) {
- // Get sm from db
- Submodel sm = (Submodel) getSubmodel();
- // Add element
- sm.addSubmodelElement(elem);
- writeSubmodelInDB(sm);
- }
-
- private ISubmodelElement getTopLevelSubmodelElement(String idShort) {
- Submodel sm = (Submodel) getSubmodel();
- Map submodelElements = sm.getSubmodelElements();
- ISubmodelElement element = submodelElements.get(idShort);
- if (element == null) {
- throw new ResourceNotFoundException("The element \"" + idShort + "\" could not be found");
- }
- return convertSubmodelElement(element);
- }
-
- @SuppressWarnings("unchecked")
- private ISubmodelElement convertSubmodelElement(ISubmodelElement element) {
- // FIXME: Convert internal data structure of ISubmodelElement
- Map elementMap = (Map) element;
- IModelProvider elementProvider = new SubmodelElementProvider(new VABMapProvider(elementMap));
- Object elementVABObj = elementProvider.getValue("");
- return SubmodelElement.createAsFacade((Map) elementVABObj);
- }
-
- private void deleteTopLevelSubmodelElement(String idShort) {
- // Get sm from db
- Submodel sm = (Submodel) getSubmodel();
- // Remove element
-
- deleteAllFilesFromGridFsIfIsFileSubmodelElement(idShort, sm);
-
- sm.getSubmodelElements().remove(idShort);
- writeSubmodelInDB(sm);
-
- }
-
- @SuppressWarnings("unchecked")
- private void deleteAllFilesFromGridFsIfIsFileSubmodelElement(String idShort, Submodel sm) {
- Map submodelElement = (Map) sm.getSubmodelElement(idShort);
- if (!File.isFile(submodelElement))
- return;
- File file = File.createAsFacade(submodelElement);
- GridFSBucket bucket = getGridFSBucket();
- bucket.find(Filters.eq("filename", file.getValue())).forEach(gridFile -> bucket.delete(gridFile.getObjectId()));
- }
-
- @Override
- public Collection getOperations() {
- Submodel sm = (Submodel) getSubmodel();
- return sm.getOperations().values();
- }
-
- private void addNestedSubmodelElement(List idShorts, ISubmodelElement elem) {
- Submodel sm = (Submodel) getSubmodel();
- // > 1 idShorts => add new sm element to an existing sm element
- if (idShorts.size() > 1) {
- idShorts = idShorts.subList(0, idShorts.size() - 1);
- // Get parent SM element if more than 1 idShort
- ISubmodelElement parentElement = getNestedSubmodelElement(sm, idShorts);
- if (parentElement instanceof SubmodelElementCollection) {
- ((SubmodelElementCollection) parentElement).addSubmodelElement(elem);
- writeSubmodelInDB(sm);
- }
- } else {
- // else => directly add it to the submodel
- sm.addSubmodelElement(elem);
- writeSubmodelInDB(sm);
- }
- }
-
- @Override
- public Collection getSubmodelElements() {
- Submodel sm = (Submodel) getSubmodel();
- return sm.getSubmodelElements().values();
- }
-
- @SuppressWarnings("unchecked")
- private void updateSubmodelElementInDB(List idShorts, Object newValue) {
- Submodel sm = (Submodel) getSubmodel();
- ISubmodelElement element = getNestedSubmodelElement(sm, idShorts);
-
- IModelProvider mapProvider = new VABLambdaProvider((Map) element);
- SubmodelElementProvider smeProvider = new SubmodelElementProvider(mapProvider);
-
- smeProvider.setValue(Property.VALUE, newValue);
- ISubmodelElement updatedElement = SubmodelElementFacadeFactory
- .createSubmodelElement((Map) smeProvider.getValue(""));
-
- sm.addSubmodelElement(updatedElement);
-
- writeSubmodelInDB(sm);
- }
-
- @Override
- public void uploadSubmodelElementFile(String idShortPath, InputStream fileStream) {
- String[] splitted = VABPathTools.splitPath(idShortPath);
- List idShorts = Arrays.asList(splitted);
- Submodel sm = (Submodel) getSubmodel();
- ISubmodelElement element = getNestedSubmodelElement(sm, idShorts);
- String fileName = updateFileInDB(fileStream, element, idShortPath);
- updateSubmodelElementInDB(idShorts, fileName);
- }
-
- @SuppressWarnings("unchecked")
- private String updateFileInDB(InputStream newValue, ISubmodelElement element, String idShortPath) {
- File file = File.createAsFacade((Map) element);
- GridFSBucket bucket = getGridFSBucket();
- String fileName = constructFileName(file, idShortPath);
- deleteAllDuplicateFiles(bucket, fileName);
- bucket.uploadFromStream(fileName, newValue);
- return fileName;
- }
-
- private void deleteAllDuplicateFiles(GridFSBucket bucket, String fileName) {
- bucket.find(Filters.eq("filename", fileName)).forEach(gridFile -> bucket.delete(gridFile.getObjectId()));
- }
-
- private GridFSBucket getGridFSBucket() {
- MongoDatabase database = client.getDatabase(config.getDatabase());
- GridFSBucket bucket = GridFSBuckets.create(database, config.getFileCollection());
- return bucket;
- }
-
- private Object getTopLevelSubmodelElementValue(String idShort) {
- Submodel sm = (Submodel) getSubmodel();
- return getElementProvider(sm, idShort).getValue("/value");
- }
-
- @SuppressWarnings("unchecked")
- private Object getNestedSubmodelElementValue(List idShorts) {
- ISubmodelElement lastElement = getNestedSubmodelElement(idShorts);
- IModelProvider mapProvider = new VABLambdaProvider((Map) lastElement);
- return new SubmodelElementProvider(mapProvider).getValue("/value");
- }
-
- @SuppressWarnings("unchecked")
- protected Object unwrapParameter(Object parameter) {
- if (parameter instanceof Map, ?>) {
- Map map = (Map) parameter;
- // Parameters have a strictly defined order and may not be omitted at all.
- // Enforcing the structure with valueType is ok, but we should unwrap null
- // values, too.
- if (map.get("valueType") != null && map.containsKey("value")) {
- return map.get("value");
- }
- }
- return parameter;
- }
-
- @SuppressWarnings("unchecked")
- private static SubmodelElementProvider getElementProvider(Submodel sm, String idShort) {
- ISubmodelElement elem = sm.getSubmodelElement(idShort);
- IModelProvider mapProvider = new VABMapProvider((Map) elem);
- return new SubmodelElementProvider(mapProvider);
- }
-
- private ISubmodelElement getNestedSubmodelElement(Submodel sm, List idShorts) {
- Map elemMap = sm.getSubmodelElements();
- // Get last nested submodel element
- for (int i = 0; i < idShorts.size() - 1; i++) {
- String idShort = idShorts.get(i);
- ISubmodelElement elem = elemMap.get(idShort);
- if (elem instanceof SubmodelElementCollection) {
- elemMap = ((SubmodelElementCollection) elem).getSubmodelElements();
- } else {
- throw new ResourceNotFoundException(
- idShort + " in the nested submodel element path could not be resolved.");
- }
- }
- String lastIdShort = idShorts.get(idShorts.size() - 1);
- if (!elemMap.containsKey(lastIdShort)) {
- throw new ResourceNotFoundException(
- lastIdShort + " in the nested submodel element path could not be resolved.");
- }
- return elemMap.get(lastIdShort);
- }
-
- private ISubmodelElement getNestedSubmodelElement(List idShorts) {
- // Get sm from db
- Submodel sm = (Submodel) getSubmodel();
- // Get nested sm element from this sm
- return convertSubmodelElement(getNestedSubmodelElement(sm, idShorts));
- }
-
- private void deleteNestedSubmodelElement(List idShorts) {
- if (idShorts.size() == 1) {
- deleteSubmodelElement(idShorts.get(0));
- return;
- }
-
- // Get sm from db
- Submodel sm = (Submodel) getSubmodel();
- // Get parent collection
- List parentIds = idShorts.subList(0, idShorts.size() - 1);
- ISubmodelElement parentElement = getNestedSubmodelElement(sm, parentIds);
- // Remove element
- SubmodelElementCollection coll = (SubmodelElementCollection) parentElement;
- coll.deleteSubmodelElement(idShorts.get(idShorts.size() - 1));
- writeSubmodelInDB(sm);
+ @Deprecated
+ public MongoDBSubmodelAPI(String submodelIdentificationId) {
+ this(DEFAULT_CONFIG_PATH, submodelIdentificationId);
}
- private Object invokeNestedOperationAsync(List idShorts, Object... params) {
- // not possible to invoke operations on a submodel that is stored in a db
- throw new MalformedRequestException("Invoke not supported by this backend");
+ @Deprecated
+ public MongoDBSubmodelAPI(String submodelIdentificationId, DelegatedInvocationManager invocationHelper) {
+ this(DEFAULT_CONFIG_PATH, submodelIdentificationId, invocationHelper);
}
- @Override
- public Object getOperationResult(String idShort, String requestId) {
- // not possible to invoke operations on a submodel that is stored in a db
- throw new MalformedRequestException("Invoke not supported by this backend");
+ @Deprecated
+ public MongoDBSubmodelAPI(String resourceConfigPath, String submodelIdentificationId, DelegatedInvocationManager invocationHelper) {
+ super(createSubmodelStorageAPI(createConfig(resourceConfigPath)), submodelIdentificationId, invocationHelper);
+ this.config = createConfig(resourceConfigPath);
+ this.setConfiguration(config);
+ this.setSubmodelId(submodelIdentificationId);
+ this.invocationHelper = invocationHelper;
}
- @Override
- public ISubmodelElement getSubmodelElement(String idShortPath) {
- if (idShortPath.contains("/")) {
- String[] splitted = VABPathTools.splitPath(idShortPath);
- List idShorts = Arrays.asList(splitted);
- return getNestedSubmodelElement(idShorts);
- } else {
- return getTopLevelSubmodelElement(idShortPath);
- }
+ private static BaSyxStorageAPI createSubmodelStorageAPI(BaSyxMongoDBConfiguration config) {
+ MongoDBBaSyxStorageAPIFactory storageAPIFactory = new MongoDBBaSyxStorageAPIFactory<>(config, Submodel.class, config.getSubmodelCollection());
+ return storageAPIFactory.create();
}
- @Override
- public void deleteSubmodelElement(String idShortPath) {
- if (idShortPath.contains("/")) {
- String[] splitted = VABPathTools.splitPath(idShortPath);
- List idShorts = Arrays.asList(splitted);
- deleteNestedSubmodelElement(idShorts);
- } else {
- deleteTopLevelSubmodelElement(idShortPath);
- }
+ private static BaSyxStorageAPI createSubmodelStorageAPI(BaSyxMongoDBConfiguration config, MongoClient client) {
+ MongoDBBaSyxStorageAPIFactory storageAPIFactory = new MongoDBBaSyxStorageAPIFactory<>(config, Submodel.class, config.getSubmodelCollection(), client);
+ return storageAPIFactory.create();
}
- @Override
- public void updateSubmodelElement(String idShortPath, Object newValue) {
- String[] splitted = VABPathTools.splitPath(idShortPath);
- List idShorts = Arrays.asList(splitted);
- updateSubmodelElementInDB(idShorts, newValue);
+ private static BaSyxMongoDBConfiguration createConfig(String resourceConfigPath) {
+ BaSyxMongoDBConfiguration config = new BaSyxMongoDBConfiguration();
+ config.loadFromResource(resourceConfigPath);
+ return config;
}
/**
- * Returns the updated Submodel or null if not found
+ * Sets the db configuration for the submodel API.
*
- * @param sm
- * @return
+ * @param config
*/
- private Submodel writeSubmodelInDB(Submodel sm) {
- Query hasId = query(where(SMIDPATH).is(smId));
- return mongoOps.findAndReplace(hasId, sm, collection);
- }
-
- @Override
- public Object getSubmodelElementValue(String idShortPath) {
- if (idShortPath.contains("/")) {
- String[] splitted = VABPathTools.splitPath(idShortPath);
- List idShorts = Arrays.asList(splitted);
- return getNestedSubmodelElementValue(idShorts);
- } else {
- return getTopLevelSubmodelElementValue(idShortPath);
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Object invokeOperation(String idShortPath, Object... params) {
- Operation operation = (Operation) SubmodelElementFacadeFactory
- .createSubmodelElement((Map) getSubmodelElement(idShortPath));
- if (!DelegatedInvocationManager.isDelegatingOperation(operation)) {
- throw new MalformedRequestException("This backend supports only delegating operations.");
- }
- return invocationHelper.invokeDelegatedOperation(operation, params);
- }
-
- @Override
- public Object invokeAsync(String idShortPath, Object... params) {
- String[] splitted = VABPathTools.splitPath(idShortPath);
- List idShorts = Arrays.asList(splitted);
- return invokeNestedOperationAsync(idShorts, params);
- }
-
- @Override
- public void addSubmodelElement(String idShortPath, ISubmodelElement elem) {
- String[] splitted = VABPathTools.splitPath(idShortPath);
- List idShorts = Arrays.asList(splitted);
- addNestedSubmodelElement(idShorts, elem);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public java.io.File getSubmodelElementFile(String idShortPath) {
- try {
- Map submodelElement = (Map) getSubmodelElement(idShortPath);
- File fileSubmodelElement = File.createAsFacade(submodelElement);
- GridFSBucket bucket = getGridFSBucket();
- String fileName = constructFileName(fileSubmodelElement, idShortPath);
- java.io.File file = new java.io.File(fileName);
- FileOutputStream fileOutputStream;
- fileOutputStream = new FileOutputStream(file);
- bucket.downloadToStream(fileName, fileOutputStream);
- return file;
- } catch (FileNotFoundException e) {
- throw new ResourceNotFoundException("The File Submodel Element does not contain a File");
- }
- }
-
- private String constructFileName(File file, String idShortPath) {
- Submodel sm = (Submodel) getSubmodel();
- return sm.getIdentification().getId() + "-" + idShortPath.replaceAll("/", "-") + getFileExtension(file);
- }
-
- private String getFileExtension(File file) {
- MimeTypes allTypes = MimeTypes.getDefaultMimeTypes();
- try {
- MimeType mimeType = allTypes.forName(file.getMimeType());
- return mimeType.getExtension();
- } catch (MimeTypeException e) {
- e.printStackTrace();
- return "";
- }
+ public void setConfiguration(BaSyxMongoDBConfiguration config) {
+ this.storageApi = createSubmodelStorageAPI(config);
}
-}
+}
\ No newline at end of file
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAPIFactory.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAPIFactory.java
index 6b11b1f7..af864a80 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAPIFactory.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAPIFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2022 the Eclipse BaSyx Authors
+ * Copyright (C) 2022, 2023 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -44,16 +44,17 @@ public class MongoDBSubmodelAPIFactory implements ISubmodelAPIFactory {
private BaSyxMongoDBConfiguration config;
private MongoClient client;
- @Deprecated
- public MongoDBSubmodelAPIFactory(BaSyxMongoDBConfiguration config) {
- this(config, MongoClients.create(config.getConnectionUrl()));
- }
-
public MongoDBSubmodelAPIFactory(BaSyxMongoDBConfiguration config, MongoClient client) {
this.config = config;
this.client = client;
}
+ @Deprecated
+ public MongoDBSubmodelAPIFactory(BaSyxMongoDBConfiguration config) {
+ this(config, MongoClients.create(config.getConnectionUrl()));
+ }
+
+ @Deprecated
@Override
public ISubmodelAPI getSubmodelAPI(Submodel submodel) {
MongoDBSubmodelAPI api = new MongoDBSubmodelAPI(config, submodel.getIdentification().getId(), client);
@@ -61,4 +62,8 @@ public ISubmodelAPI getSubmodelAPI(Submodel submodel) {
return api;
}
+ public ISubmodelAPI create(Submodel submodel) {
+ return getSubmodelAPI(submodel);
+ }
+
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAggregator.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAggregator.java
index e8d74184..d92a5913 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAggregator.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAggregator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2022 the Eclipse BaSyx Authors
+ * Copyright (C) 2022, 2023 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -25,64 +25,146 @@
package org.eclipse.basyx.components.aas.mongodb;
-import static org.springframework.data.mongodb.core.query.Criteria.where;
-import static org.springframework.data.mongodb.core.query.Query.query;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;
import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPI;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPIFactory;
import org.eclipse.basyx.submodel.aggregator.SubmodelAggregator;
import org.eclipse.basyx.submodel.metamodel.api.ISubmodel;
import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
+import org.eclipse.basyx.submodel.metamodel.api.reference.IKey;
+import org.eclipse.basyx.submodel.metamodel.api.reference.IReference;
+import org.eclipse.basyx.submodel.metamodel.map.Submodel;
+import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPI;
import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPIFactory;
+import org.eclipse.basyx.submodel.restapi.vab.VABSubmodelAPIFactory;
import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.client.MongoClient;
-import com.mongodb.client.MongoClients;
/**
* Extends the {@link SubmodelAggregator} for the needs of MongoDB
*
- * @author schnicke
+ * @author schnicke, jungjan, witt
*
*/
public class MongoDBSubmodelAggregator extends SubmodelAggregator {
+ private MongoDBBaSyxStorageAPI storageApi;
+ private MongoDBBaSyxStorageAPI aasStorageApi;
+ private IIdentifier shellId;
- private String smCollection;
- private MongoTemplate mongoOps;
-
- @Deprecated
- public MongoDBSubmodelAggregator(ISubmodelAPIFactory smApiFactory, BaSyxMongoDBConfiguration config) {
- this(smApiFactory, config, MongoClients.create(config.getConnectionUrl()));
+ public MongoDBSubmodelAggregator(ISubmodelAPIFactory submodelApiFactory, BaSyxMongoDBConfiguration config, MongoClient client) {
+ this(submodelApiFactory, MongoDBBaSyxStorageAPIFactory.create(config.getSubmodelCollection(), Submodel.class, config, client));
}
- public MongoDBSubmodelAggregator(ISubmodelAPIFactory smApiFactory, BaSyxMongoDBConfiguration config, MongoClient client) {
- super(smApiFactory);
+ public MongoDBSubmodelAggregator(ISubmodelAPIFactory submodelApiFactory, BaSyxMongoDBConfiguration config, MongoClient client, IIdentifier shellId) {
+ this(submodelApiFactory, MongoDBBaSyxStorageAPIFactory.create(config.getSubmodelCollection(), Submodel.class, config, client));
+ aasStorageApi = MongoDBBaSyxStorageAPIFactory.create(config.getAASCollection(), AssetAdministrationShell.class, config, client);
+ this.shellId = shellId;
+ }
- smCollection = config.getSubmodelCollection();
+ public MongoDBSubmodelAggregator(ISubmodelAPIFactory submodelApiFactory, MongoDBBaSyxStorageAPI storageApi) {
+ super(submodelApiFactory);
+ this.storageApi = storageApi;
+ }
- mongoOps = new MongoTemplate(client, config.getDatabase());
+ @Deprecated
+ public MongoDBSubmodelAggregator(ISubmodelAPIFactory submodelApiFactory, BaSyxMongoDBConfiguration config) {
+ this(submodelApiFactory, MongoDBBaSyxStorageAPIFactory.create(config.getSubmodelCollection(), Submodel.class, config));
}
@Override
- public void deleteSubmodelByIdentifier(IIdentifier identifier) {
- super.deleteSubmodelByIdentifier(identifier);
- deleteSubmodelFromDB(identifier);
+ public void deleteSubmodelByIdentifier(IIdentifier submodelIdentifier) {
+ storageApi.delete(submodelIdentifier.getId());
}
@Override
public void deleteSubmodelByIdShort(String idShort) {
- try {
- ISubmodel sm = getSubmodelbyIdShort(idShort);
- super.deleteSubmodelByIdShort(idShort);
- deleteSubmodelFromDB(sm.getIdentification());
- } catch (ResourceNotFoundException e) {
- // Nothing to do
+ ISubmodel submodel = getSubmodelbyIdShort(idShort);
+ storageApi.delete(submodel.getIdentification().getId());
+ }
+
+ @Override
+ public Collection getSubmodelList() {
+ if (shellId == null)
+ return returnAllSubmodels();
+
+ AssetAdministrationShell shell = aasStorageApi.retrieve(shellId.getId());
+ Collection submodelRefs = shell.getSubmodelReferences();
+
+ if (submodelRefs.isEmpty()) {
+ return findSubmodelsWithGivenParentId();
}
+ List submodelIds = submodelRefs.stream().map(ref -> {
+ return getLastKeyFromReference(ref).getValue();
+ }).collect(Collectors.toList());
+
+ return submodelIds.stream().map(sm -> {
+ return storageApi.retrieve(sm);
+ }).collect(Collectors.toList());
+ }
+
+ private List returnAllSubmodels() {
+ return storageApi.retrieveAll().stream().map(submodel -> (ISubmodel) submodel).collect(Collectors.toList());
+ }
+
+ private List findSubmodelsWithGivenParentId(){
+ return storageApi.retrieveAll().stream().filter(submodel -> {
+ IReference parentRef = submodel.getParent();
+ return (parentRef != null) && (parentRef.getKeys().get(0).getValue().equals(shellId.getId()));
+ }).collect(Collectors.toList());
+ }
+
+ private IKey getLastKeyFromReference(IReference reference) {
+ List keys = reference.getKeys();
+ IKey lastKey = keys.get(keys.size() - 1);
+ return lastKey;
+ }
+
+ @Override
+ public ISubmodel getSubmodel(IIdentifier identifier) throws ResourceNotFoundException {
+ return storageApi.retrieve(identifier.getId());
+ }
+
+ @Override
+ public void createSubmodel(Submodel submodel) {
+ storageApi.createOrUpdate(submodel);
+ }
+
+ @Override
+ public void updateSubmodel(Submodel submodel) throws ResourceNotFoundException {
+ storageApi.createOrUpdate(submodel);
+ }
+
+ @Override
+ public void createSubmodel(ISubmodelAPI submodelAPI) {
+ storageApi.createOrUpdate((Submodel) submodelAPI.getSubmodel());
+ }
+
+ @Override
+ public ISubmodel getSubmodelbyIdShort(String idShort) throws ResourceNotFoundException {
+ Optional submodelOptional = getSubmodelList().stream().filter(submodel -> {
+ return submodel.getIdShort().equals(idShort);
+ }).findAny();
+ if (submodelOptional.isEmpty())
+ throw new ResourceNotFoundException("The submodel with idShort '" + idShort + "' could not be found");
+ return submodelOptional.get();
}
- private void deleteSubmodelFromDB(IIdentifier identifier) {
- Query hasId = query(where(MongoDBSubmodelAPI.SMIDPATH).is(identifier.getId()));
- mongoOps.remove(hasId, smCollection);
+ @Override
+ public ISubmodelAPI getSubmodelAPIById(IIdentifier identifier) throws ResourceNotFoundException {
+ Submodel submodel = (Submodel) getSubmodel(identifier);
+ return new VABSubmodelAPIFactory().create(submodel);
+ }
+
+ @Override
+ public ISubmodelAPI getSubmodelAPIByIdShort(String idShort) throws ResourceNotFoundException {
+ Submodel submodel = (Submodel) getSubmodelbyIdShort(idShort);
+ return new VABSubmodelAPIFactory().create(submodel);
}
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAggregatorFactory.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAggregatorFactory.java
index 0bf1bc2e..d5c63dfc 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAggregatorFactory.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/java/org/eclipse/basyx/components/aas/mongodb/MongoDBSubmodelAggregatorFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2022 the Eclipse BaSyx Authors
+ * Copyright (C) 2022, 2023 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -46,25 +46,25 @@ public class MongoDBSubmodelAggregatorFactory implements ISubmodelAggregatorFact
private ISubmodelAPIFactory submodelAPIFactory;
private MongoClient client;
- @Deprecated
- public MongoDBSubmodelAggregatorFactory(BaSyxMongoDBConfiguration config, ISubmodelAPIFactory submodelAPIFactory) {
- this(config, submodelAPIFactory, MongoClients.create(config.getConnectionUrl()));
- }
-
public MongoDBSubmodelAggregatorFactory(BaSyxMongoDBConfiguration config, ISubmodelAPIFactory submodelAPIFactory, MongoClient client) {
this.config = config;
this.client = client;
this.submodelAPIFactory = submodelAPIFactory;
}
+ @Deprecated
+ public MongoDBSubmodelAggregatorFactory(BaSyxMongoDBConfiguration config, ISubmodelAPIFactory submodelAPIFactory) {
+ this(config, submodelAPIFactory, MongoClients.create(config.getConnectionUrl()));
+ }
+
@Override
public ISubmodelAggregator create() {
return new MongoDBSubmodelAggregator(submodelAPIFactory, config, client);
}
@Override
- public ISubmodelAggregator create(IIdentifier ignored) {
- return create();
+ public ISubmodelAggregator create(IIdentifier shellId) {
+ return new MongoDBSubmodelAggregator(submodelAPIFactory, config, client, shellId);
}
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aas.properties b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aas.properties
index e26cc8aa..025d0018 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aas.properties
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aas.properties
@@ -59,12 +59,12 @@ aas.aasxUpload=Enabled
# registry.path=http://localhost:4000/registry/
# #############################
-# Host
+# External URL
# #############################
-# Host specifies the endpoint of the deployed AAS component
-# If host is empty, the registered AAS endpoint is derived from the context properties
+# The external URL specifies the endpoint of the deployed AAS component
+# If it is empty, the registered AAS endpoint is derived from the context properties
-# registry.host=
+# aas.externalurl=
# #############################
# Submodels
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aasx/a.aasx b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aasx/a.aasx
new file mode 100644
index 00000000..a22b8a14
Binary files /dev/null and b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aasx/a.aasx differ
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aasx/b.aasx b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aasx/b.aasx
new file mode 100644
index 00000000..2cb692bd
Binary files /dev/null and b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/main/resources/aasx/b.aasx differ
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/AASXSuite.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/AASXSuite.java
index c838afe9..ef9d88c4 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/AASXSuite.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/AASXSuite.java
@@ -39,6 +39,7 @@
import org.eclipse.basyx.aas.manager.ConnectedAssetAdministrationShellManager;
import org.eclipse.basyx.aas.metamodel.connected.ConnectedAssetAdministrationShell;
import org.eclipse.basyx.aas.metamodel.map.descriptor.AASDescriptor;
+import org.eclipse.basyx.aas.metamodel.map.descriptor.CustomId;
import org.eclipse.basyx.aas.metamodel.map.descriptor.ModelUrn;
import org.eclipse.basyx.aas.metamodel.map.descriptor.SubmodelDescriptor;
import org.eclipse.basyx.aas.registration.api.IAASRegistry;
@@ -72,11 +73,25 @@ public abstract class AASXSuite {
protected static final String aasShortId = "Festo_3S7PM0CP4BD";
protected static final ModelUrn aasId = new ModelUrn("smart.festo.com/demo/aas/1/1/454576463545648365874");
protected static final ModelUrn smId = new ModelUrn("www.company.com/ids/sm/4343_5072_7091_3242");
- protected static final String smShortId = "Nameplate";
+ protected static final String smIdShort = "Nameplate";
+
+ protected static final String aasAIdShort = "aasA";
+ protected static final String smAIdShort = "a";
+ protected static final CustomId aasAId = new CustomId("AssetAdministrationShell---51A6D8AE");
+ protected static final CustomId smAId = new CustomId("fileTestA");
+ protected static final String aasBIdShort = "aasB";
+ protected static final String smBIdShort = "b";
+ protected static final CustomId aasBId = new CustomId("AssetAdministrationShell---51A6D8AF");
+ protected static final CustomId smBId = new CustomId("fileTestB");
+ protected static final String fileShortIdPath = "file";
// Has to be individualized by each test inheriting from this suite
protected static String aasEndpoint;
protected static String smEndpoint;
+ protected static String aasAEndpoint;
+ protected static String smAEndpoint;
+ protected static String aasBEndpoint;
+ protected static String smBEndpoint;
protected static String rootEndpoint;
private ConnectedAssetAdministrationShellManager manager;
@@ -93,8 +108,14 @@ public void setUp() {
// Create a dummy registry to test integration of XML AAS
aasRegistry = new InMemoryRegistry();
AASDescriptor descriptor = new AASDescriptor(aasShortId, aasId, aasEndpoint);
- descriptor.addSubmodelDescriptor(new SubmodelDescriptor(smShortId, smId, smEndpoint));
+ descriptor.addSubmodelDescriptor(new SubmodelDescriptor(smIdShort, smId, smEndpoint));
aasRegistry.register(descriptor);
+ AASDescriptor descriptorA = new AASDescriptor(aasAIdShort, aasAId, aasAEndpoint);
+ descriptorA.addSubmodelDescriptor(new SubmodelDescriptor(smAIdShort, smAId, smAEndpoint));
+ aasRegistry.register(descriptorA);
+ AASDescriptor descriptorB = new AASDescriptor(aasBIdShort, aasBId, aasBEndpoint);
+ descriptorB.addSubmodelDescriptor(new SubmodelDescriptor(smBIdShort, smBId, smBEndpoint));
+ aasRegistry.register(descriptorB);
// Create a ConnectedAssetAdministrationShell using a
// ConnectedAssetAdministrationShellManager
@@ -110,18 +131,18 @@ public void testGetSingleAAS() throws Exception {
@Test
public void testGetSingleSubmodel() throws Exception {
- ISubmodel subModel = getConnectedSubmodel();
- assertEquals(smShortId, subModel.getIdShort());
+ ISubmodel subModel = manager.retrieveSubmodel(aasId, smId);
+ assertEquals(smIdShort, subModel.getIdShort());
}
@Test
public void testGetSingleModule() throws Exception {
- final String FILE_ENDING = "files/aasx/Nameplate/marking_rcm.jpg";
- final String FILE_PATH = rootEndpoint + "files/aasx/Nameplate/marking_rcm.jpg";
+ final String FILE_ENDING = "basyx-temp/aasx0/files/aasx/Nameplate/marking_rcm.jpg";
+ final String FILE_PATH = rootEndpoint + "basyx-temp/aasx0/files/aasx/Nameplate/marking_rcm.jpg";
checkFile(FILE_PATH);
// Get the submdoel nameplate
- ISubmodel nameplate = getConnectedSubmodel();
+ ISubmodel nameplate = manager.retrieveSubmodel(aasId, smId);
// Get the submodel element collection marking_rcm
ConnectedSubmodelElementCollection marking_rcm = (ConnectedSubmodelElementCollection) nameplate.getSubmodelElements().get("Marking_RCM");
Collection values = marking_rcm.getValue();
@@ -139,6 +160,24 @@ public void testGetSingleModule() throws Exception {
}
}
}
+
+ @Test
+ public void testCollidingFiles() throws Exception {
+ final String FILE_ENDING_A = "basyx-temp/aasx1/files/aasx/files/text.txt";
+ final String FILE_ENDING_B = "basyx-temp/aasx2/files/aasx/files/text.txt";
+
+ checkFile(rootEndpoint + FILE_ENDING_A);
+ checkFile(rootEndpoint + FILE_ENDING_B);
+
+ ISubmodel smA = manager.retrieveSubmodel(aasAId, smAId);
+ ISubmodel smB = manager.retrieveSubmodel(aasBId, smBId);
+
+ String fileAValue = (String) smA.getSubmodelElement("file").getValue();
+ String fileBValue = (String) smB.getSubmodelElement("file").getValue();
+
+ assertTrue(fileAValue.endsWith(FILE_ENDING_A));
+ assertTrue(fileBValue.endsWith(FILE_ENDING_B));
+ }
@Test
public void testAllFiles() throws Exception {
@@ -187,14 +226,4 @@ private void checkFile(String absolutePath) {
private ConnectedAssetAdministrationShell getConnectedAssetAdministrationShell() throws Exception {
return manager.retrieveAAS(aasId);
}
-
- /**
- * Gets the connected Submodel
- *
- * @return connected SM
- * @throws Exception
- */
- private ISubmodel getConnectedSubmodel() {
- return manager.retrieveSubmodel(aasId, smId);
- }
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/TestAASXAASServer.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/TestAASXAASServer.java
index b8baca8d..cd8e3473 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/TestAASXAASServer.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/TestAASXAASServer.java
@@ -26,6 +26,7 @@
import java.io.IOException;
import java.net.URISyntaxException;
+import java.net.URLEncoder;
import java.nio.file.Paths;
import javax.servlet.ServletException;
@@ -59,7 +60,7 @@ public static void setUpClass() throws ParserConfigurationException, SAXExceptio
// Setup component's test configuration
BaSyxContextConfiguration contextConfig = new BaSyxContextConfiguration();
contextConfig.loadFromResource(BaSyxContextConfiguration.DEFAULT_CONFIG_PATH);
- BaSyxAASServerConfiguration aasConfig = new BaSyxAASServerConfiguration(AASServerBackend.INMEMORY, "aasx/01_Festo.aasx");
+ BaSyxAASServerConfiguration aasConfig = new BaSyxAASServerConfiguration(AASServerBackend.INMEMORY, "[\"aasx/01_Festo.aasx\", \"aasx/a.aasx\", \"aasx/b.aasx\"]");
String docBasepath = Paths.get(FileUtils.getTempDirectory().getAbsolutePath(), AASXToMetamodelConverter.TEMP_DIRECTORY).toAbsolutePath().toString();
contextConfig.setDocBasePath(docBasepath);
@@ -70,7 +71,13 @@ public static void setUpClass() throws ParserConfigurationException, SAXExceptio
rootEndpoint = contextConfig.getUrl() + "/";
aasEndpoint = rootEndpoint + "/" + AASAggregatorProvider.PREFIX + "/" + aasId.getEncodedURN() + "/aas";
- smEndpoint = aasEndpoint + "/submodels/" + smShortId + "/submodel";
+ smEndpoint = aasEndpoint + "/submodels/" + smIdShort + "/submodel";
+ String encodedAasAId = URLEncoder.encode(aasAId.getId(), "UTF-8");
+ aasAEndpoint = rootEndpoint + "/" + AASAggregatorProvider.PREFIX + "/" + encodedAasAId + "/aas";
+ smAEndpoint = aasAEndpoint + "/submodels/" + smAIdShort + "/submodel";
+ String encodedAasBId = URLEncoder.encode(aasBId.getId(), "UTF-8");
+ aasBEndpoint = rootEndpoint + "/" + AASAggregatorProvider.PREFIX + "/" + encodedAasBId + "/aas";
+ smBEndpoint = aasBEndpoint + "/submodels/" + smBIdShort + "/submodel";
logger.info("AAS URL for servlet test: " + aasEndpoint);
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/TestAASXPackageManager.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/TestAASXPackageManager.java
index 1efce60e..79d10494 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/TestAASXPackageManager.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/TestAASXPackageManager.java
@@ -145,6 +145,7 @@ public void testCheckAasxConverter() {
/**
* Creates a new .aasx using the AASXFactory and tries to parse it
*/
+ @SuppressWarnings("resource")
@Test
public void testLoadGeneratedAASX() throws InvalidFormatException, IOException, ParserConfigurationException, SAXException, TransformerException, URISyntaxException {
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBAAASAPI.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBAAASAPI.java
new file mode 100644
index 00000000..c7770652
--- /dev/null
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBAAASAPI.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+package org.eclipse.basyx.regression.AASServer.mongodb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collection;
+
+import org.eclipse.basyx.aas.metamodel.api.IAssetAdministrationShell;
+import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;
+import org.eclipse.basyx.aas.metamodel.map.descriptor.CustomId;
+import org.eclipse.basyx.components.aas.mongodb.MongoDBAASAPI;
+import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPI;
+import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
+import org.eclipse.basyx.submodel.metamodel.api.reference.IReference;
+import org.eclipse.basyx.submodel.metamodel.map.Submodel;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @author jungjan, witt
+ *
+ */
+public class TestMongoDBAAASAPI {
+ private static MongoDBAASAPI shellAPI;
+ private final static String COLLECTION_NAME = "testCollection";
+ private final static BaSyxMongoDBConfiguration config = new BaSyxMongoDBConfiguration();
+ private static MongoDBBaSyxStorageAPI mongoDBStorageAPI;
+ private final static String SHELL_IDENTIFICATION_ID = "testIdentificationId";
+
+ @SuppressWarnings("deprecation")
+ @BeforeClass
+ public static void setUpClass() {
+ mongoDBStorageAPI = new MongoDBBaSyxStorageAPI<>(COLLECTION_NAME, AssetAdministrationShell.class, config);
+ shellAPI = new MongoDBAASAPI(mongoDBStorageAPI, SHELL_IDENTIFICATION_ID);
+ }
+
+ @Before
+ public void before() {
+ Collection shells = mongoDBStorageAPI.retrieveAll();
+ shells.forEach(shell -> mongoDBStorageAPI.delete(shell.getIdentification().getId()));
+ }
+
+ @Test
+ public void setAndGetAAS() {
+ String idShort = "testIdShort";
+
+ IIdentifier identification = new CustomId(SHELL_IDENTIFICATION_ID);
+ AssetAdministrationShell expectedShell = new AssetAdministrationShell(idShort, identification, null);
+
+ shellAPI.setAAS(expectedShell);
+ AssetAdministrationShell resultShell = (AssetAdministrationShell) shellAPI.getAAS();
+
+ assertEquals(expectedShell, resultShell);
+ }
+
+ @Test
+ public void addSubmodel() {
+ String idShortShell = "testIdShortShell";
+ String idShortSubmodel = "testIdShortSubmodel";
+
+ IIdentifier identification = new CustomId(SHELL_IDENTIFICATION_ID);
+
+ AssetAdministrationShell expectedShell = new AssetAdministrationShell(idShortShell, identification, null);
+ shellAPI.setAAS(expectedShell);
+
+ Submodel expectedSubmodel = new Submodel(idShortSubmodel, identification);
+ IReference testReference = expectedSubmodel.getReference();
+
+ expectedShell.addSubmodelReference(testReference);
+ shellAPI.addSubmodel(testReference);
+
+ Object resultShell = shellAPI.getAAS();
+
+ assertEquals(expectedShell, resultShell);
+
+ }
+
+ @Test
+ public void removeSubmodel() {
+ String idShortShell = "testIdShortShell";
+ String idShortSubmodel = "testIdShortSubmodel";
+
+ IIdentifier identification = new CustomId(SHELL_IDENTIFICATION_ID);
+
+ AssetAdministrationShell testShell = new AssetAdministrationShell(idShortShell, identification, null);
+
+ Submodel expectedSubmodel = new Submodel(idShortSubmodel, identification);
+ IReference testReference = expectedSubmodel.getReference();
+
+ shellAPI.setAAS(testShell);
+ shellAPI.addSubmodel(testReference);
+ shellAPI.removeSubmodel(expectedSubmodel.getIdentification().getId());
+
+ IAssetAdministrationShell resultShell = shellAPI.getAAS();
+ Collection submodelReferences = resultShell.getSubmodelReferences();
+ assertTrue(submodelReferences.isEmpty());
+ }
+}
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBAggregator.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBAggregator.java
index f655c944..380a0db0 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBAggregator.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBAggregator.java
@@ -109,7 +109,11 @@ public static void setUpClass() throws ParserConfigurationException, SAXExceptio
component.setRegistry(registry);
component.startComponent();
+ }
+ @Override
+ public void setup() {
+ super.setup();
createAssetAdministrationShell(AAS_ID);
createSubmodel(SM_IDSHORT, SM_IDENTIFICATION, AAS_ID);
}
@@ -152,14 +156,11 @@ private static void createSubmodel(String smIdShort, Identifier smIdentifier, St
@Test
public void testDeleteReachesDatabase() {
- final BaSyxMongoDBConfiguration config = new BaSyxMongoDBConfiguration();
- config.loadFromResource(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH);
-
- final MongoClient client = MongoClients.create(config.getConnectionUrl());
+ final MongoClient client = MongoClients.create(mongoDBConfig.getConnectionUrl());
- final MongoTemplate mongoOps = new MongoTemplate(client, config.getDatabase());
+ final MongoTemplate mongoOps = new MongoTemplate(client, mongoDBConfig.getDatabase());
- final String aasCollection = config.getAASCollection();
+ final String aasCollection = mongoDBConfig.getAASCollection();
final IAASAggregator aggregator = getAggregator();
@@ -198,16 +199,16 @@ public void testDeleteReachesDatabase() {
@SuppressWarnings("deprecation")
@Override
protected IAASAggregator getAggregator() {
- MongoDBAASAggregator aggregator = new MongoDBAASAggregator(BaSyxMongoDBConfiguration.DEFAULT_CONFIG_PATH);
+ MongoDBAASAggregator aggregator = new MongoDBAASAggregator(mongoDBConfig, registry);
aggregator.reset();
-
return aggregator;
}
@SuppressWarnings("deprecation")
@Test
public void checkInitialSetupAfterCreatingAndRegisteringAasAndSubmodel() {
- MongoDBAASAggregator aggregator = new MongoDBAASAggregator(mongoDBConfig);
+ MongoDBAASAggregator aggregator = new MongoDBAASAggregator(mongoDBConfig, registry);
+
ISubmodel persistentSubmodel = getSubmodelFromAggregator(aggregator, AAS_ID, SM_IDSHORT);
assertEquals(SM_IDSHORT, persistentSubmodel.getIdShort());
@@ -248,9 +249,6 @@ private void assertSubmodelsAreResolvedCorrectly(ISubmodel persistentSubmodel, I
}
private void createAASWithSubmodelWithCollidingIdShort() {
- createAssetAdministrationShell(AAS_ID);
- createSubmodel(SM_IDSHORT, SM_IDENTIFICATION, AAS_ID);
-
createAssetAdministrationShell(AAS_ID_2);
createSubmodel(SM_IDSHORT, SM_IDENTIFICATION_2, AAS_ID_2);
}
@@ -273,6 +271,7 @@ public void checkNoExceptionIsObservedAfterPassingRegistry() {
restartAasServer();
MongoDBAASAggregator aggregator = new MongoDBAASAggregator(mongoDBConfig, registry);
+
MultiSubmodelProvider aasProvider = (MultiSubmodelProvider) getAssetAdministrationShellProviderFromMongoDBAggregator(aggregator, AAS_ID, SM_IDSHORT);
Map submodelObject = (Map) aasProvider.getValue(PREFIX_SUBMODEL_PATH + SM_IDSHORT + SUFFIX_SUBMODEL_PATH);
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBServer.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBServer.java
index 2fb38045..d6fc380c 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBServer.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBServer.java
@@ -130,7 +130,7 @@ public void testAggregatorPersistency() throws Exception {
createAssetAdministrationShell();
createSubmodel();
- MongoDBAASAggregator aggregator = new MongoDBAASAggregator(mongoDBConfig);
+ MongoDBAASAggregator aggregator = new MongoDBAASAggregator(mongoDBConfig, aasRegistry);
ISubmodel persistentSM = getSubmodelFromAggregator(aggregator);
assertEquals(SM_IDSHORT, persistentSM.getIdShort());
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBSubmodelAPI.java b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBSubmodelAPI.java
index c631ad49..3068c067 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBSubmodelAPI.java
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/java/org/eclipse/basyx/regression/AASServer/mongodb/TestMongoDBSubmodelAPI.java
@@ -31,14 +31,21 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
import org.eclipse.basyx.aas.metamodel.map.descriptor.CustomId;
import org.eclipse.basyx.components.aas.mongodb.MongoDBSubmodelAPI;
import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.submodel.metamodel.api.submodelelement.ISubmodelElement;
import org.eclipse.basyx.submodel.metamodel.map.Submodel;
import org.eclipse.basyx.submodel.metamodel.map.qualifier.LangStrings;
+import org.eclipse.basyx.submodel.metamodel.map.submodelelement.SubmodelElementCollection;
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.File;
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.MultiLanguageProperty;
+import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.Property;
+import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
import org.junit.Test;
import com.mongodb.MongoGridFSException;
@@ -85,7 +92,7 @@ public void fileSubmodelElementFileUpload() throws FileNotFoundException {
java.io.File value = submodelAPI.getSubmodelElementFile("fileSmeIdShort");
- assertEquals("mySubmodelId-fileSmeIdShort.xml", value.getName());
+ assertEquals("#"+ Objects.hashCode(submodelAPI.getSubmodelId())+"#mySubmodelId-fileSmeIdShort.xml", value.getName());
assertEquals(expected.length(), value.length());
}
@@ -104,6 +111,43 @@ public void fileSubmodelElementFileIsAutomaticallyDeleted() throws FileNotFoundE
bucket.downloadToStream("fileSmeIdShort.xml", os);
}
+ @SuppressWarnings("unchecked")
+ @Test
+ public void submodelElementInCollection() {
+ MongoDBSubmodelAPI submodelAPI = createAPIWithPreconfiguredSubmodel();
+ SubmodelElementCollection collection = new SubmodelElementCollection("collection");
+ MultiLanguageProperty mlprop = new MultiLanguageProperty("myMLP");
+ collection.addSubmodelElement(mlprop);
+ submodelAPI.addSubmodelElement(collection);
+
+ LangStrings expected = new LangStrings("de", "Hallo!");
+ submodelAPI.updateSubmodelElement(collection.getIdShort() + "/" + mlprop.getIdShort(), expected);
+
+ Object value = submodelAPI.getSubmodelElementValue(collection.getIdShort() + "/" + mlprop.getIdShort());
+
+ Collection updatedSubmodelElements = submodelAPI.getSubmodelElements();
+ Map updatedCollectionMap = (Map) submodelAPI.getSubmodelElement("collection");
+ Collection> collectionValue = (Collection>) updatedCollectionMap.get(Property.VALUE);
+
+ assertEquals(1, updatedSubmodelElements.size());
+ assertEquals(1, collectionValue.size());
+ assertEquals(expected, value);
+ }
+
+ @Test(expected = ResourceNotFoundException.class)
+ public void submodelElementInCollectionNotExistingAsHighLevelElement() {
+ MongoDBSubmodelAPI submodelAPI = createAPIWithPreconfiguredSubmodel();
+ SubmodelElementCollection collection = new SubmodelElementCollection("collection");
+ MultiLanguageProperty mlprop = new MultiLanguageProperty("myMLP");
+ collection.addSubmodelElement(mlprop);
+ submodelAPI.addSubmodelElement(collection);
+
+ LangStrings expected = new LangStrings("de", "Hallo!");
+ submodelAPI.updateSubmodelElement(collection.getIdShort() + "/" + mlprop.getIdShort(), expected);
+
+ submodelAPI.getSubmodelElementValue(mlprop.getIdShort());
+ }
+
private void uploadDummyFile(MongoDBSubmodelAPI submodelAPI, String idShort) throws FileNotFoundException {
File file = new File("application/xml");
file.setValue("");
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/.env b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/.env
index 6a62d5eb..425f95c4 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/.env
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/.env
@@ -28,7 +28,7 @@ BASYX_IMAGE_NAME=eclipsebasyx/aas-server
# ##################
# The image tag of the image that is build for this component
-BASYX_IMAGE_TAG=1.4.0
+BASYX_IMAGE_TAG=1.5.0
# ##################
# Container Name
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aasServerConfig.properties b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aasServerConfig.properties
index c52a96cf..3119afa2 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aasServerConfig.properties
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aasServerConfig.properties
@@ -59,7 +59,7 @@ registry.path=http://localhost:4000/registry
# Host specifies the endpoint of the deployed AAS component
# If host is empty, the registered AAS endpoint is derived from the context properties
-#registry.host=localhost
+# aas.externalurl=
# #############################
# Submodels
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_multiple_different_source.properties b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_multiple_different_source.properties
index 5f4f3676..3efd83aa 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_multiple_different_source.properties
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_multiple_different_source.properties
@@ -58,7 +58,7 @@ aas.aasxUpload=Enabled
# Host specifies the endpoint of the deployed AAS component
# If host is empty, the registered AAS endpoint is derived from the context properties
-# registry.host=
+# aas.externalurl=
# #############################
# Submodels
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_single_json_source.properties b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_single_json_source.properties
index c59c459a..37ea65cb 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_single_json_source.properties
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_single_json_source.properties
@@ -58,7 +58,7 @@ aas.aasxUpload=Enabled
# Host specifies the endpoint of the deployed AAS component
# If host is empty, the registered AAS endpoint is derived from the context properties
-# registry.host=
+# aas.externalurl=
# #############################
# Submodels
diff --git a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_single_source.properties b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_single_source.properties
index 2283d0fa..6988052a 100644
--- a/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_single_source.properties
+++ b/basyx.components/basyx.components.docker/basyx.components.AASServer/src/test/resources/aas_single_source.properties
@@ -58,7 +58,7 @@ aas.aasxUpload=Enabled
# Host specifies the endpoint of the deployed AAS component
# If host is empty, the registered AAS endpoint is derived from the context properties
-# registry.host=
+# aas.externalurl=
# #############################
# Submodels
diff --git a/basyx.components/basyx.components.docker/basyx.components.registry/pom.xml b/basyx.components/basyx.components.docker/basyx.components.registry/pom.xml
index a5dadd74..c55aaf23 100644
--- a/basyx.components/basyx.components.docker/basyx.components.registry/pom.xml
+++ b/basyx.components/basyx.components.docker/basyx.components.registry/pom.xml
@@ -6,7 +6,7 @@
org.eclipse.basyx
basyx.components.docker
- 1.4.0
+ 1.5.0
basyx.components.registry
@@ -77,21 +77,21 @@
org.mongodb
mongodb-driver-sync
- 4.9.0
+ 4.10.2
org.springframework.data
spring-data-mongodb
- 3.4.10
+ 3.4.15
io.moquette
moquette-broker
- 0.16
+ 0.17
test
@@ -112,14 +112,14 @@
com.fasterxml.jackson.core
jackson-core
- 2.14.2
+ 2.15.2
com.fasterxml.jackson.core
jackson-annotations
- 2.14.2
+ 2.15.2
diff --git a/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/configuration/BaSyxRegistryConfiguration.java b/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/configuration/BaSyxRegistryConfiguration.java
index 3e999e90..b5269b7c 100644
--- a/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/configuration/BaSyxRegistryConfiguration.java
+++ b/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/configuration/BaSyxRegistryConfiguration.java
@@ -24,6 +24,7 @@
******************************************************************************/
package org.eclipse.basyx.components.registry.configuration;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -73,16 +74,16 @@ public static Map getDefaultProperties() {
}
public BaSyxRegistryConfiguration() {
- super(getDefaultProperties());
+ super(getDefaultProperties(), Collections.emptyList());
}
public BaSyxRegistryConfiguration(RegistryBackend backend) {
- super(getDefaultProperties());
+ super(getDefaultProperties(), Collections.emptyList());
setRegistryBackend(backend);
}
public BaSyxRegistryConfiguration(Map values) {
- super(values);
+ super(values, Collections.emptyList());
}
public void loadFromEnvironmentVariables() {
diff --git a/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/mongodb/MongoDBRegistryHandler.java b/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/mongodb/MongoDBRegistryHandler.java
index e5fa19f7..5f4bfeae 100644
--- a/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/mongodb/MongoDBRegistryHandler.java
+++ b/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/mongodb/MongoDBRegistryHandler.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2021 the Eclipse BaSyx Authors
+ * Copyright (C) 2021, 2023 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -32,30 +32,26 @@
import org.eclipse.basyx.aas.metamodel.map.descriptor.AASDescriptor;
import org.eclipse.basyx.aas.registration.memory.IRegistryHandler;
import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPI;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPIFactory;
import org.eclipse.basyx.submodel.metamodel.api.identifier.IIdentifier;
import org.eclipse.basyx.submodel.metamodel.map.identifier.Identifier;
import org.eclipse.basyx.submodel.metamodel.map.qualifier.Identifiable;
import org.springframework.data.mongodb.core.MongoOperations;
-import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
-import com.mongodb.client.MongoClient;
-import com.mongodb.client.MongoClients;
-
/**
* A registry handler based on MongoDB
*
- * @author espen
+ * @author espen, jungjan, witt
*/
public class MongoDBRegistryHandler implements IRegistryHandler {
private static final String DEFAULT_CONFIG_PATH = "mongodb.properties";
- protected BaSyxMongoDBConfiguration config;
- protected MongoOperations mongoOps;
- protected String collection;
+ private MongoDBBaSyxStorageAPI storageApi;
- private static final String AASID = Identifiable.IDENTIFICATION + "." + Identifier.ID;
- private static final String ASSETID = AASDescriptor.ASSET + "." + Identifiable.IDENTIFICATION + "." + Identifier.ID;
+ private static final String SHELL_IDENTIFICATION_ID = Identifiable.IDENTIFICATION + "." + Identifier.ID;
+ private static final String ASSET_IDENTIFICATION_ID = AASDescriptor.ASSET + "." + Identifiable.IDENTIFICATION + "." + Identifier.ID;
/**
* Receives the path of the configuration.properties file in it's constructor.
@@ -63,7 +59,7 @@ public class MongoDBRegistryHandler implements IRegistryHandler {
* @param config
*/
public MongoDBRegistryHandler(BaSyxMongoDBConfiguration config) {
- this.setConfiguration(config);
+ this.initStorageApi(config);
}
/**
@@ -71,9 +67,13 @@ public MongoDBRegistryHandler(BaSyxMongoDBConfiguration config) {
* resource.
*/
public MongoDBRegistryHandler(String resourceConfigPath) {
- config = new BaSyxMongoDBConfiguration();
+ this(configFromResource(resourceConfigPath));
+ }
+
+ private static BaSyxMongoDBConfiguration configFromResource(String resourceConfigPath) {
+ BaSyxMongoDBConfiguration config = new BaSyxMongoDBConfiguration();
config.loadFromResource(resourceConfigPath);
- this.setConfiguration(config);
+ return config;
}
/**
@@ -84,67 +84,58 @@ public MongoDBRegistryHandler() {
}
public void setConfiguration(BaSyxMongoDBConfiguration config) {
- this.config = config;
- MongoClient client = MongoClients.create(config.getConnectionUrl());
- this.mongoOps = new MongoTemplate(client, config.getDatabase());
- this.collection = config.getRegistryCollection();
+ this.initStorageApi(config);
+ }
+
+ private void initStorageApi(BaSyxMongoDBConfiguration config) {
+ String collectionName = config.getRegistryCollection();
+ MongoDBBaSyxStorageAPIFactory storageApiFactory = new MongoDBBaSyxStorageAPIFactory<>(config, AASDescriptor.class, collectionName);
+ this.storageApi = storageApiFactory.create();
}
@Override
public boolean contains(IIdentifier identifier) {
- String id = identifier.getId();
+ String identificationId = identifier.getId();
Criteria hasId = new Criteria();
- hasId.orOperator(where(AASID).is(id), where(ASSETID).is(id));
- return mongoOps.exists(query(hasId), collection);
+ hasId.orOperator(where(SHELL_IDENTIFICATION_ID).is(identificationId), where(ASSET_IDENTIFICATION_ID).is(identificationId));
+
+ return getStorageConnection().exists(query(hasId), this.storageApi.getCollectionName());
+ }
+
+ private MongoOperations getStorageConnection() {
+ return (MongoOperations) this.storageApi.getStorageConnection();
}
@Override
public void remove(IIdentifier identifier) {
- String id = identifier.getId();
+ String indentificationId = identifier.getId();
Criteria hasId = new Criteria();
- hasId.orOperator(where(AASID).is(id), where(ASSETID).is(id));
- mongoOps.remove(query(hasId), collection);
+ hasId.orOperator(where(SHELL_IDENTIFICATION_ID).is(indentificationId), where(ASSET_IDENTIFICATION_ID).is(indentificationId));
+ getStorageConnection().remove(query(hasId), this.storageApi.getCollectionName());
}
@Override
public void insert(AASDescriptor descriptor) {
- mongoOps.insert(descriptor, collection);
- // mongoOps added "_id" to descriptor after insert
- removeMongoDBSpecificId(descriptor);
+ this.update(descriptor);
}
@Override
public void update(AASDescriptor descriptor) {
- String aasId = descriptor.getIdentifier().getId();
- Object result = mongoOps.findAndReplace(query(where(AASID).is(aasId)), descriptor, collection);
- if (result == null) {
- insert(descriptor);
- }
+ this.storageApi.createOrUpdate(descriptor);
}
@Override
public AASDescriptor get(IIdentifier identifier) {
- String id = identifier.getId();
+ String indentificationId = identifier.getId();
Criteria hasId = new Criteria();
- hasId.orOperator(where(AASID).is(id), where(ASSETID).is(id));
- AASDescriptor result = mongoOps.findOne(query(hasId), AASDescriptor.class, collection);
- removeMongoDBSpecificId(result);
-
- return result;
- }
+ hasId.orOperator(where(SHELL_IDENTIFICATION_ID).is(indentificationId), where(ASSET_IDENTIFICATION_ID).is(indentificationId));
- private void removeMongoDBSpecificId(AASDescriptor result) {
- if (result != null) {
- // Remove mongoDB-specific map attribute from AASDescriptor
- result.remove("_id");
- }
+ AASDescriptor result = getStorageConnection().findOne(query(hasId), AASDescriptor.class, this.storageApi.getCollectionName());
+ return this.storageApi.handleMongoDbIdAttribute(result);
}
@Override
public List getAll() {
- List result = mongoOps.findAll(AASDescriptor.class, collection);
- // Remove mongoDB-specific map attribute from AASDescriptor
- result.forEach(desc -> desc.remove("_id"));
- return result;
+ return (List) this.storageApi.retrieveAll();
}
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/mongodb/MongoDBTaggedDirectory.java b/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/mongodb/MongoDBTaggedDirectory.java
index 68676631..5db11836 100644
--- a/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/mongodb/MongoDBTaggedDirectory.java
+++ b/basyx.components/basyx.components.docker/basyx.components.registry/src/main/java/org/eclipse/basyx/components/registry/mongodb/MongoDBTaggedDirectory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2021-2022 the Eclipse BaSyx Authors
+ * Copyright (C) 2021, 2022, 2023 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -64,18 +64,18 @@ private boolean isTaggedDescriptor(ModelDescriptor descriptor) {
}
@Override
- public void registerSubmodel(IIdentifier aas, TaggedSubmodelDescriptor descriptor) {
- super.register(aas, descriptor);
+ public void registerSubmodel(IIdentifier shellIdentifier, TaggedSubmodelDescriptor descriptor) {
+ super.register(shellIdentifier, descriptor);
addSubmodelTags(descriptor);
- updateTagMap(aas, descriptor);
+ updateTagMap(shellIdentifier, descriptor);
}
- private void updateTagMap(IIdentifier aas, TaggedSubmodelDescriptor descriptor) {
+ private void updateTagMap(IIdentifier shellIdentifier, TaggedSubmodelDescriptor descriptor) {
tagMap.values().forEach(tagSet -> {
- tagSet.forEach(tagDesc -> {
- if (descriptorEqualsToGivenAASId(aas, tagDesc)) {
- if (!containsSubmodelDescriptor(descriptor, tagDesc))
- tagDesc.addSubmodelDescriptor(descriptor);
+ tagSet.forEach(taggedDescriptor -> {
+ if (descriptorEqualsToGivenAASId(shellIdentifier, taggedDescriptor)) {
+ if (!containsSubmodelDescriptor(descriptor, taggedDescriptor))
+ taggedDescriptor.addSubmodelDescriptor(descriptor);
}
});
});
@@ -85,7 +85,7 @@ private boolean containsSubmodelDescriptor(TaggedSubmodelDescriptor descriptor,
return tagDesc.getSubmodelDescriptorFromIdShort(descriptor.getIdShort()) != null;
}
- private boolean descriptorEqualsToGivenAASId(IIdentifier aas, TaggedAASDescriptor tagDesc) {
- return tagDesc.getIdentifier().getId().equals(aas.getId());
+ private boolean descriptorEqualsToGivenAASId(IIdentifier shellIdentifier, TaggedAASDescriptor taggedDescriptor) {
+ return taggedDescriptor.getIdentifier().getId().equals(shellIdentifier.getId());
}
}
diff --git a/basyx.components/basyx.components.docker/basyx.components.registry/src/test/resources/.env b/basyx.components/basyx.components.docker/basyx.components.registry/src/test/resources/.env
index 733ae6fa..8fdd96e3 100644
--- a/basyx.components/basyx.components.docker/basyx.components.registry/src/test/resources/.env
+++ b/basyx.components/basyx.components.docker/basyx.components.registry/src/test/resources/.env
@@ -28,7 +28,7 @@ BASYX_IMAGE_NAME=eclipsebasyx/aas-registry
# ##################
# The image tag of the image that is build for this component
-BASYX_IMAGE_TAG=1.4.0
+BASYX_IMAGE_TAG=1.5.0
# ##################
# Container Name
diff --git a/basyx.components/basyx.components.docker/pom.xml b/basyx.components/basyx.components.docker/pom.xml
index 1962072a..0eb8d0ec 100644
--- a/basyx.components/basyx.components.docker/pom.xml
+++ b/basyx.components/basyx.components.docker/pom.xml
@@ -7,7 +7,7 @@
org.eclipse.basyx
basyx.components
- 1.4.0
+ 1.5.0
basyx.components.docker
@@ -28,7 +28,7 @@
org.codehaus.mojo
properties-maven-plugin
- 1.1.0
+ 1.2.0
initialize
@@ -95,7 +95,7 @@
io.fabric8
docker-maven-plugin
- 0.42.0
+ 0.43.4
@@ -170,7 +170,7 @@
org.apache.maven.plugins
maven-failsafe-plugin
- 3.0.0
+ 3.1.2
@@ -223,7 +223,7 @@
org.eclipse.basyx
basyx.components.lib
- 1.4.0
+ 1.5.0
diff --git a/basyx.components/basyx.components.lib/pom.xml b/basyx.components/basyx.components.lib/pom.xml
index 1042b9f4..dab3f087 100644
--- a/basyx.components/basyx.components.lib/pom.xml
+++ b/basyx.components/basyx.components.lib/pom.xml
@@ -6,7 +6,7 @@
org.eclipse.basyx
basyx.components
- 1.4.0
+ 1.5.0
basyx.components.lib
@@ -80,22 +80,36 @@
42.6.0
+
+
+ org.mongodb
+ mongodb-driver-sync
+ 4.10.2
+
+
+
+
+ org.springframework.data
+ spring-data-mongodb
+ 3.4.15
+
+
org.camunda.bpm
camunda-engine
- 7.18.0
+ 7.19.0
org.camunda.bpm.model
camunda-bpmn-model
- 7.18.0
+ 7.19.0
com.h2database
h2
- 2.2.220
+ 2.2.224
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxConfiguration.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxConfiguration.java
index baae5470..b0d1e27b 100644
--- a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxConfiguration.java
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxConfiguration.java
@@ -43,16 +43,33 @@ public class BaSyxConfiguration {
// Properties in this configuration
private Map values;
+ private List propertiesExcludedFromLogging;
+
+ @Deprecated
/**
* Constructor that takes the configuration's default values. All the keys in
* the map are the name of the properties that are stored and loaded in this
* configuration.
+ *
+ * @param defaultValues
+ * @deprecated Use {@link #BaSyxConfiguration(Map, List)} to ensure proper
+ * exclusion is configured
*/
public BaSyxConfiguration(Map defaultValues) {
this.values = defaultValues;
}
+ /**
+ *
+ * @param defaultValues
+ * @param propertiesExcludedFromLogging
+ */
+ public BaSyxConfiguration(Map defaultValues, List propertiesExcludedFromLogging) {
+ this(defaultValues);
+ this.propertiesExcludedFromLogging = propertiesExcludedFromLogging;
+ }
+
public static InputStream getResourceStream(String relativeResourcePath) {
ClassLoader classLoader = BaSyxConfiguration.class.getClassLoader();
return classLoader.getResourceAsStream(relativeResourcePath);
@@ -150,15 +167,14 @@ public void loadFromProperties(Properties properties) {
for (Object property : properties.keySet()) {
String propertyName = (String) property;
String loaded = properties.getProperty(propertyName);
- if (values.containsKey(propertyName)) {
- logger.info(propertyName + ": '" + loaded + "'");
- } else {
- logger.debug(propertyName + ": '" + loaded + "'");
- }
+
+ logPropertyVariable(propertyName, loaded);
+
values.put(propertyName, loaded);
}
}
+
/**
* Method for subclasses to read specific environment variables
*
@@ -182,7 +198,7 @@ protected void loadFromEnvironmentVariables(String prefix, String... properties)
for (String propName : properties) {
String result = getEnvironmentVariable(prefix, propName, usesDeprecatedNamingConvention);
if (result != null) {
- logger.info("Environment - " + propName + ": " + result);
+ logEnvironmentVariable(propName, result);
setProperty(propName, result);
}
}
@@ -191,6 +207,26 @@ protected void loadFromEnvironmentVariables(String prefix, String... properties)
}
}
+ private void logPropertyVariable(String propertyName, String result) {
+ if (isPropertyExcludedFromLogging(propertyName)) {
+ result = "*****";
+ }
+
+ logger.info("Property File - " + propertyName + ": '" + result + "'");
+ }
+
+ private void logEnvironmentVariable(String propertyName, String result) {
+ if (isPropertyExcludedFromLogging(propertyName)) {
+ result = "*****";
+ }
+
+ logger.info("Environment - " + propertyName + ": " + result);
+ }
+
+ private boolean isPropertyExcludedFromLogging(String propertyName) {
+ return propertiesExcludedFromLogging.contains(propertyName);
+ }
+
private String getEnvironmentVariable(String prefix, String propName, boolean usesDeprecatedNamingConvention) {
if (usesDeprecatedNamingConvention) {
return getEnvironmentVariableDeprecatedNamingConvention(prefix, propName);
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxContextConfiguration.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxContextConfiguration.java
index cfe157dc..59799622 100644
--- a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxContextConfiguration.java
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxContextConfiguration.java
@@ -24,7 +24,9 @@
******************************************************************************/
package org.eclipse.basyx.components.configuration;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.eclipse.basyx.vab.modelprovider.VABPathTools;
@@ -85,14 +87,14 @@ public static Map getDefaultProperties() {
* Empty Constructor - use default values
*/
public BaSyxContextConfiguration() {
- super(getDefaultProperties());
+ super(getDefaultProperties(), getPropertiesExcludedFromLogging());
}
/**
* Constructor with predefined value map
*/
public BaSyxContextConfiguration(Map values) {
- super(values);
+ super(values, getPropertiesExcludedFromLogging());
}
/**
@@ -287,4 +289,8 @@ private String getProtocol() {
}
return "http://";
}
+
+ private static List getPropertiesExcludedFromLogging() {
+ return Collections.singletonList(SSL_KEY_PASSWORD);
+ }
}
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxDockerConfiguration.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxDockerConfiguration.java
index 12ea074e..6971281e 100644
--- a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxDockerConfiguration.java
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxDockerConfiguration.java
@@ -24,6 +24,7 @@
******************************************************************************/
package org.eclipse.basyx.components.configuration;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -68,14 +69,14 @@ public static Map getDefaultProperties() {
* Empty Constructor - use default values
*/
public BaSyxDockerConfiguration() {
- super(getDefaultProperties());
+ super(getDefaultProperties(), Collections.emptyList());
}
/**
* Constructor with predefined value map
*/
public BaSyxDockerConfiguration(Map values) {
- super(values);
+ super(values, Collections.emptyList());
}
/**
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxMongoDBConfiguration.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxMongoDBConfiguration.java
index e0e04788..7cac1e79 100644
--- a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxMongoDBConfiguration.java
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxMongoDBConfiguration.java
@@ -24,7 +24,9 @@
******************************************************************************/
package org.eclipse.basyx.components.configuration;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -74,14 +76,14 @@ public static Map getDefaultProperties() {
* Constructor with predefined value map
*/
public BaSyxMongoDBConfiguration(Map values) {
- super(values);
+ super(values, getPropertiesExcludedFromLogging());
}
/**
* Empty Constructor - use default values
*/
public BaSyxMongoDBConfiguration() {
- super(getDefaultProperties());
+ super(getDefaultProperties(), getPropertiesExcludedFromLogging());
}
/**
@@ -202,4 +204,8 @@ public String getFileCollection() {
public void setFileCollection(String fileCollection) {
setProperty(FILE_COLLECTION, fileCollection);
}
+
+ private static List getPropertiesExcludedFromLogging() {
+ return Collections.singletonList(CONNECTIONURL);
+ }
}
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxMqttConfiguration.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxMqttConfiguration.java
index d53ddf9d..43fb22c6 100644
--- a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxMqttConfiguration.java
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxMqttConfiguration.java
@@ -24,6 +24,7 @@
******************************************************************************/
package org.eclipse.basyx.components.configuration;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -81,14 +82,14 @@ public static Map getDefaultProperties() {
* Constructor with predefined value map
*/
public BaSyxMqttConfiguration(Map values) {
- super(values);
+ super(values, getPropertiesExcludedFromLogging());
}
/**
* Empty Constructor - use default values
*/
public BaSyxMqttConfiguration() {
- super(getDefaultProperties());
+ super(getDefaultProperties(), getPropertiesExcludedFromLogging());
}
/**
@@ -209,6 +210,10 @@ public void setWhitelist(String submodelId, List elementIds) {
}
public String getClientId() {
- return getProperty(CLIENT_ID);
+ return getProperty(CLIENT_ID);
+ }
+
+ private static List getPropertiesExcludedFromLogging() {
+ return Collections.singletonList(PASS);
}
}
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxSQLConfiguration.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxSQLConfiguration.java
index 936ec09f..dd77a62f 100644
--- a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxSQLConfiguration.java
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxSQLConfiguration.java
@@ -24,7 +24,9 @@
******************************************************************************/
package org.eclipse.basyx.components.configuration;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -71,14 +73,14 @@ public static Map getDefaultProperties() {
* Constructor with predefined value map
*/
public BaSyxSQLConfiguration(Map values) {
- super(values);
+ super(values, getPropertiesExcludedFromLogging());
}
/**
* Empty Constructor - use default values
*/
public BaSyxSQLConfiguration() {
- super(getDefaultProperties());
+ super(getDefaultProperties(), getPropertiesExcludedFromLogging());
}
/**
@@ -153,4 +155,8 @@ public String getPrefix() {
public void setPrefix(String prefix) {
setProperty(PREFIX, prefix);
}
+
+ private static List getPropertiesExcludedFromLogging() {
+ return Collections.singletonList(PASS);
+ }
}
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxSecurityConfiguration.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxSecurityConfiguration.java
index aab653cc..ebe8fff5 100644
--- a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxSecurityConfiguration.java
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/configuration/BaSyxSecurityConfiguration.java
@@ -24,6 +24,7 @@
******************************************************************************/
package org.eclipse.basyx.components.configuration;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -78,14 +79,14 @@ public static Map getDefaultProperties() {
* Constructor with predefined value map
*/
public BaSyxSecurityConfiguration(Map values) {
- super(values);
+ super(values, Collections.emptyList());
}
/**
* Empty Constructor - use default values
*/
public BaSyxSecurityConfiguration() {
- super(getDefaultProperties());
+ super(getDefaultProperties(), Collections.emptyList());
}
/**
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/internal/mongodb/MongoDBBaSyxStorageAPI.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/internal/mongodb/MongoDBBaSyxStorageAPI.java
new file mode 100644
index 00000000..5df97a9a
--- /dev/null
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/internal/mongodb/MongoDBBaSyxStorageAPI.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.basyx.components.internal.mongodb;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.extensions.internal.storage.BaSyxStorageAPI;
+import org.eclipse.basyx.submodel.metamodel.api.submodelelement.ISubmodelElement;
+import org.eclipse.basyx.submodel.metamodel.map.Submodel;
+import org.eclipse.basyx.submodel.metamodel.map.identifier.Identifier;
+import org.eclipse.basyx.submodel.metamodel.map.qualifier.Identifiable;
+import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.File;
+import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
+import org.springframework.data.mongodb.core.FindAndReplaceOptions;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Query;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+import com.mongodb.client.gridfs.GridFSBucket;
+import com.mongodb.client.result.DeleteResult;
+
+/**
+ * Provides BaSyxStorageAPI implementation for MongoDB
+ *
+ * @author fischer, jungjan, witt
+ *
+ * @param
+ */
+public class MongoDBBaSyxStorageAPI extends BaSyxStorageAPI {
+ private final String INDEX_KEY = Identifiable.IDENTIFICATION + "." + Identifier.ID;
+
+ protected BaSyxMongoDBConfiguration config;
+ protected MongoClient client;
+ protected MongoOperations mongoOps;
+
+ /**
+ * @deprecated Please use the other constructor with MongoClient client.
+ * Using this constructor may lead to inefficient resource utilization.
+ */
+ @Deprecated
+ public MongoDBBaSyxStorageAPI(String collectionName, Class type, BaSyxMongoDBConfiguration config) {
+ this(collectionName, type, config, MongoClients.create(config.getConnectionUrl()));
+ }
+
+ public MongoDBBaSyxStorageAPI(String collectionName, Class type, BaSyxMongoDBConfiguration config, MongoClient client) {
+ super(collectionName, type);
+ this.config = config;
+ this.client = client;
+ this.mongoOps = new MongoTemplate(client, config.getDatabase());
+ }
+
+ @Override
+ public T createOrUpdate(T obj) {
+ String key = getKey(obj);
+ if (alreadyExists(key)) {
+ return update(obj, key);
+ }
+
+ T created = mongoOps.insert(obj, getCollectionName());
+ return handleMongoDbIdAttribute(created);
+ }
+
+ private boolean alreadyExists(String key) {
+ Query hasId = query(where(INDEX_KEY).is(key));
+ return mongoOps.exists(hasId, getCollectionName());
+ }
+
+ @Override
+ public T update(T obj, String key) {
+ T replaced = findAndReplaceIfExists(obj, key);
+ if (replaced == null) {
+ logger.warn("Could not execute update for key {} as it does not exist in the database; Creating new entry...", key);
+ return createOrUpdate(obj);
+ }
+ replaced = handleMongoDbIdAttribute(replaced);
+ return replaced;
+ }
+
+ private T findAndReplaceIfExists(T obj, String key) {
+ Query hasId = query(where(INDEX_KEY).is(key));
+ FindAndReplaceOptions replacementOptions = setupReplacemantOptionsToReturnNew();
+ T replaced = mongoOps.findAndReplace(hasId, obj, replacementOptions.returnNew(), getCollectionName());
+ return replaced;
+ }
+
+ private FindAndReplaceOptions setupReplacemantOptionsToReturnNew() {
+ FindAndReplaceOptions replacementOptions = FindAndReplaceOptions.empty();
+ replacementOptions.returnNew();
+ return replacementOptions;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T handleMongoDbIdAttribute(T data) {
+ if (data instanceof Map)
+ ((Map) data).remove("_id");
+ return data;
+ }
+
+ @Override
+ public boolean delete(String key) {
+ Query hasId = query(where(INDEX_KEY).is(key));
+ DeleteResult result = mongoOps.remove(hasId, getCollectionName());
+ return result.getDeletedCount() == 1L;
+ }
+
+ @Override
+ public void createCollectionIfNotExists(String collectionName) {
+ // MongoOperations implicitly creates Collections.
+ }
+
+ @Override
+ public void deleteCollection() {
+ mongoOps.dropCollection(getCollectionName());
+ }
+
+ @Override
+ public T rawRetrieve(String key) {
+ Query hasId = query(where(INDEX_KEY).is(key));
+ var result = mongoOps.findOne(hasId, TYPE, getCollectionName());
+ if (result == null) {
+ throw new ResourceNotFoundException("No Object for key '" + key + "' found in the database.");
+ }
+ result = handleMongoDbIdAttribute(result);
+ return result;
+ }
+
+ @Override
+ public java.io.File getFile(String idShortPath, String parentKey, Map objMap) {
+ try {
+ File fileSubmodelElement = File.createAsFacade(objMap);
+ GridFSBucket bucket = MongoDBFileHelper.getGridFSBucket(client, config);
+ String fileName = MongoDBFileHelper.constructFileName(parentKey, fileSubmodelElement, idShortPath);
+ java.io.File file = new java.io.File(fileName);
+ // check if file with this filename exist in MongoDB
+ // there might be older files constructed with old (=legacy) filenames, use this one instead
+ // the real file in file system still uses the new filename pattern!
+ if (!MongoDBFileHelper.fileExists(bucket, fileName)) {
+ fileName = MongoDBFileHelper.legacyFileName(parentKey, fileSubmodelElement, idShortPath);
+ }
+ try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
+ bucket.downloadToStream(fileName, fileOutputStream);
+ }
+ return file;
+ } catch (IOException e) {
+ throw new ResourceNotFoundException("The File Submodel Element does not contain a File");
+ }
+ }
+
+ @Override
+ public String writeFile(String idShortPath, String parentKey, InputStream inputStream, ISubmodelElement element) {
+ return MongoDBFileHelper.updateFileInDB(client, config, parentKey, inputStream, element, idShortPath);
+ }
+
+ @Override
+ public void deleteFile(Submodel submodel, String idShort) {
+ MongoDBFileHelper.deleteAllFilesFromGridFsIfIsFileSubmodelElement(client, config, submodel, idShort);
+ }
+
+ @Override
+ public Collection rawRetrieveAll() {
+ Collection data = mongoOps.findAll(TYPE, getCollectionName());
+ data = data.stream()
+ .map(this::handleMongoDbIdAttribute)
+ .collect(Collectors.toList());
+ return data;
+ }
+
+ @Override
+ public Object getStorageConnection() {
+ return mongoOps;
+ }
+
+ public MongoClient getClient() {
+ return client;
+ }
+}
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/internal/mongodb/MongoDBBaSyxStorageAPIFactory.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/internal/mongodb/MongoDBBaSyxStorageAPIFactory.java
new file mode 100644
index 00000000..ed20484c
--- /dev/null
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/internal/mongodb/MongoDBBaSyxStorageAPIFactory.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.basyx.components.internal.mongodb;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+
+/**
+ *
+ * @author fischer, jung
+ *
+ * @param
+ * Generic type of the objects to be managed by the produced API
+ */
+public class MongoDBBaSyxStorageAPIFactory {
+ private static Map knownClients = new HashMap<>();
+
+ private final BaSyxMongoDBConfiguration config;
+ private final Class type;
+ private final String collectionName;
+ private final MongoClient client;
+
+ /**
+ * Constructor for a generic BaSyxMongoDBAPIFactory
+ *
+ * @param config
+ * BaSyx MongoDB Configuration
+ * @param type
+ * Must be the exact same type as the type of the generic parameter
+ * {@code }
+ * @param collectionName
+ * The name of the collection, managed by the produced API
+ */
+ public MongoDBBaSyxStorageAPIFactory(BaSyxMongoDBConfiguration config, Class type, String collectionName) {
+ this.config = config;
+ this.type = type;
+ this.collectionName = collectionName;
+ this.client = null;
+ }
+
+ /**
+ * Constructor for a generic BaSyxMongoDBAPIFactory
+ *
+ * @param config
+ * BaSyx MongoDB Configuration
+ * @param type
+ * Must be the exact same type as the type of the generic parameter
+ * {@code }
+ * @param collectionName
+ * The name of the collection, managed by the produced API
+ * @param client
+ * The client of the MongoDB connection
+ */
+ public MongoDBBaSyxStorageAPIFactory(BaSyxMongoDBConfiguration config, Class type, String collectionName, MongoClient client) {
+ this.config = config;
+ this.type = type;
+ this.collectionName = collectionName;
+ this.client = client;
+ }
+
+ /**
+ * Creates a generic MongoDBBaSyxStorageAPI. This method has been designed to
+ * ensure efficient resource utilization by reusing existing storage clients if
+ * they already exist.
+ *
+ * @param
+ * @param config
+ * BaSyx MongoDB Configuration
+ * @param type
+ * Must be the exact same type as the type of the generic parameter
+ * {@code }
+ * @param collectionName
+ * The name of the collection, managed by the produced API
+ * @param client
+ * The client of the MongoDB connection
+ * @return
+ */
+ public static synchronized MongoDBBaSyxStorageAPI create(String collectionName, Class type, BaSyxMongoDBConfiguration config, MongoClient client) {
+ String connectionUrl = config.getConnectionUrl();
+ if (!knownClients.containsKey(connectionUrl)) {
+ knownClients.put(connectionUrl, client);
+ }
+ return new MongoDBBaSyxStorageAPI(collectionName, type, config, knownClients.get(connectionUrl));
+ }
+
+ /**
+ * Creates a generic MongoDBBaSyxStorageAPI. If an appropriate MongoClient
+ * already exists, it will be reused.
+ *
+ * @param
+ * @param config
+ * BaSyx MongoDB Configuration
+ * @param type
+ * Must be the exact same type as the type of the generic parameter
+ * {@code }
+ * @param collectionName
+ * The name of the collection, managed by the produced API
+ * @return
+ */
+ public static synchronized MongoDBBaSyxStorageAPI create(String collectionName, Class type, BaSyxMongoDBConfiguration config) {
+ String connectionUrl = config.getConnectionUrl();
+ return knownClients.containsKey(connectionUrl)
+ ? create(collectionName, type, config, knownClients.get(connectionUrl))
+ : create(collectionName, type, config, createNewClient(config));
+ }
+
+ private static MongoClient createNewClient(BaSyxMongoDBConfiguration config) {
+ return MongoClients.create(config.getConnectionUrl());
+ }
+
+ /**
+ * Creates a generic MongoDBBaSyxStorageAPI. If an appropriate MongoClient
+ * already exists, it will be reused
+ *
+ * @return
+ */
+ public MongoDBBaSyxStorageAPI create() {
+ return this.client == null
+ ? MongoDBBaSyxStorageAPIFactory.create(collectionName, type, config)
+ : MongoDBBaSyxStorageAPIFactory.create(collectionName, type, config, client);
+ }
+}
diff --git a/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/internal/mongodb/MongoDBFileHelper.java b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/internal/mongodb/MongoDBFileHelper.java
new file mode 100644
index 00000000..18f602d8
--- /dev/null
+++ b/basyx.components/basyx.components.lib/src/main/java/org/eclipse/basyx/components/internal/mongodb/MongoDBFileHelper.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.basyx.components.internal.mongodb;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.apache.tika.mime.MimeType;
+import org.apache.tika.mime.MimeTypeException;
+import org.apache.tika.mime.MimeTypes;
+import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.submodel.metamodel.api.submodelelement.ISubmodelElement;
+import org.eclipse.basyx.submodel.metamodel.map.Submodel;
+import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.File;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.gridfs.GridFSBucket;
+import com.mongodb.client.gridfs.GridFSBuckets;
+import com.mongodb.client.model.Filters;
+
+/**
+ * Supports MongoDB file handling
+ *
+ * @author fischer
+ *
+ */
+public class MongoDBFileHelper {
+ private MongoDBFileHelper() {
+ }
+
+ @SuppressWarnings("unchecked")
+ public static String updateFileInDB(MongoClient client, BaSyxMongoDBConfiguration config, String submodelId, InputStream newValue, ISubmodelElement element, String idShortPath) {
+ File file = File.createAsFacade((Map) element);
+ GridFSBucket bucket = getGridFSBucket(client, config);
+ String fileName = constructFileName(submodelId, file, idShortPath);
+ deleteAllDuplicateFiles(bucket, fileName, legacyFileName(submodelId, file, idShortPath));
+ bucket.uploadFromStream(fileName, newValue);
+ return fileName;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void deleteAllFilesFromGridFsIfIsFileSubmodelElement(MongoClient client, BaSyxMongoDBConfiguration config, Submodel sm, String idShort) {
+ Map submodelElement = (Map) sm.getSubmodelElement(idShort);
+ if (!File.isFile(submodelElement))
+ return;
+ File file = File.createAsFacade(submodelElement);
+ GridFSBucket bucket = MongoDBFileHelper.getGridFSBucket(client, config);
+ deleteAllDuplicateFiles(bucket, constructFileName(sm.getIdentification().getId(), file, idShort), legacyFileName(sm.getIdentification().getId(), file, idShort));
+ }
+
+ protected static boolean fileExists(GridFSBucket bucket, String fileName) {
+ return bucket.find(Filters.eq("filename", fileName)).first() != null;
+ }
+
+ public static GridFSBucket getGridFSBucket(MongoClient client, BaSyxMongoDBConfiguration config) {
+ MongoDatabase database = client.getDatabase(config.getDatabase());
+ return GridFSBuckets.create(database, config.getFileCollection());
+ }
+
+ private static void deleteAllDuplicateFiles(GridFSBucket bucket, String... fileNames) {
+ bucket.find(Filters.or(
+ Arrays.stream(fileNames)
+ .map(fileName -> Filters.eq("filename", fileName))
+ .collect(Collectors.toList())))
+ .forEach(gridFile -> bucket.delete(gridFile.getObjectId()));
+ }
+
+ public static String constructFileName(String submodelId, File file, String idShortPath) {
+ String fileName = submodelId + "-" + idShortPath.replaceAll("/", "-") + getFileExtension(file);
+ // replace those chars that are not permitted on filesystems
+ fileName = fileName.replaceAll("[^a-zA-Z0-9-_\\.]", "_");
+ // ensure the filename is still unique to be used as key in MongoDB storage layer
+ return String.format("#%s#", Objects.hashCode(submodelId)).concat(fileName);
+ }
+ /**
+ * This method is kept for backwards compatibility to still find files from DB which where stored with old scheme.
+ * @param file the filename of this file is requested.
+ * @param idShortPath the shortId of the given file.
+ * @return the filename as it was constructed in older versions.
+ */
+ public static String legacyFileName(String submodelId, File file, String idShortPath) {
+ return submodelId + "-" + idShortPath.replaceAll("/", "-") + getFileExtension(file);
+ }
+
+
+ private static String getFileExtension(File file) {
+ MimeTypes allTypes = MimeTypes.getDefaultMimeTypes();
+ try {
+ MimeType mimeType = allTypes.forName(file.getMimeType());
+ return mimeType.getExtension();
+ } catch (MimeTypeException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+}
diff --git a/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/components/internal/mongodb/TestMongoDBBaSyxStorageAPI.java b/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/components/internal/mongodb/TestMongoDBBaSyxStorageAPI.java
new file mode 100644
index 00000000..a9e373e3
--- /dev/null
+++ b/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/components/internal/mongodb/TestMongoDBBaSyxStorageAPI.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+package org.eclipse.basyx.regression.components.internal.mongodb;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPI;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPIFactory;
+import org.eclipse.basyx.extensions.internal.storage.BaSyxStorageAPI;
+import org.eclipse.basyx.submodel.metamodel.map.Submodel;
+import org.eclipse.basyx.testsuite.regression.extensions.storage.BaSyxStorageAPISuite;
+import org.junit.After;
+import org.springframework.data.mongodb.core.MongoOperations;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+
+public class TestMongoDBBaSyxStorageAPI extends BaSyxStorageAPISuite {
+ private final static String connectionString = "mongodb://localhost:27017";
+ private final static String testSubmodelCollectioName = "testsubnmodels";
+
+ private static BaSyxMongoDBConfiguration config = createTestConfig(connectionString, testSubmodelCollectioName);
+
+ private static BaSyxMongoDBConfiguration createTestConfig(String connectionstring, String submodelcollectioname) {
+ BaSyxMongoDBConfiguration config = new BaSyxMongoDBConfiguration();
+ config.setConnectionUrl(connectionstring);
+ config.setSubmodelCollection(submodelcollectioname);
+ return config;
+ }
+
+ @After
+ public void cleanUp() {
+ this.storageAPI.deleteCollection();
+ }
+
+ @Override
+ protected BaSyxStorageAPI getStorageAPI() {
+ MongoDBBaSyxStorageAPIFactory storageAPIFactory = new MongoDBBaSyxStorageAPIFactory(config, Submodel.class, config.getSubmodelCollection());
+ return storageAPIFactory.create();
+ }
+
+ @Override
+ protected BaSyxStorageAPI getSecondStorageAPI() {
+ // Please use the MongoDBBaSyxStorageAPIFactory in production code.
+ MongoClient client = MongoClients.create(connectionString);
+ return new MongoDBBaSyxStorageAPI(testSubmodelCollectioName, Submodel.class, config, client);
+ }
+
+ @Override
+ public void createCollectionIfNotExists() {
+ // Not Implemented for MongoDBBaSyxStorageAPI as Collections are created
+ // dynamically.
+ }
+
+ @Override
+ public void deleteCollection() {
+ triggerCollectionCreation();
+ MongoOperations mongoOps = (MongoOperations) storageAPI.getStorageConnection();
+ assertTrue(mongoOps.collectionExists(testSubmodelCollectioName));
+
+ this.storageAPI.deleteCollection();
+ assertFalse(mongoOps.collectionExists(testSubmodelCollectioName));
+ }
+
+ private void triggerCollectionCreation() {
+ this.storageAPI.createOrUpdate(testSubmodel);
+ }
+}
diff --git a/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/components/internal/mongodb/TestMongoDBBaSyxStorageAPIFactory.java b/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/components/internal/mongodb/TestMongoDBBaSyxStorageAPIFactory.java
new file mode 100644
index 00000000..099e6cc1
--- /dev/null
+++ b/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/components/internal/mongodb/TestMongoDBBaSyxStorageAPIFactory.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+package org.eclipse.basyx.regression.components.internal.mongodb;
+
+import static org.junit.Assert.assertSame;
+
+import org.eclipse.basyx.components.configuration.BaSyxMongoDBConfiguration;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPI;
+import org.eclipse.basyx.components.internal.mongodb.MongoDBBaSyxStorageAPIFactory;
+import org.eclipse.basyx.testsuite.regression.extensions.storage.VABTestType;
+import org.junit.Test;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+
+public class TestMongoDBBaSyxStorageAPIFactory {
+ static BaSyxMongoDBConfiguration config = createTestConfig("mongodb://localhost:27017");
+ static MongoClient client = MongoClients.create(config.getConnectionUrl());
+
+ private static BaSyxMongoDBConfiguration createTestConfig(String connectionUrl) {
+ BaSyxMongoDBConfiguration config = new BaSyxMongoDBConfiguration();
+ config.setConnectionUrl(connectionUrl);
+ return config;
+ }
+
+ @Test
+ public void assureFactoryReusesMongoClient() throws NoSuchFieldException, SecurityException {
+ MongoDBBaSyxStorageAPI storageAPI0 = new MongoDBBaSyxStorageAPIFactory(config, VABTestType.class, "c0", client).create();
+ MongoDBBaSyxStorageAPI storageAPI1 = new MongoDBBaSyxStorageAPIFactory(config, VABTestType.class, "c1", client).create();
+ MongoDBBaSyxStorageAPI storageAPI2 = new MongoDBBaSyxStorageAPIFactory(config, VABTestType.class, "c2").create();
+ MongoDBBaSyxStorageAPI storageAPI3 = MongoDBBaSyxStorageAPIFactory.create("c3", VABTestType.class, config, client);
+ MongoDBBaSyxStorageAPI storageAPI4 = MongoDBBaSyxStorageAPIFactory.create("c4", VABTestType.class, config);
+
+ assertSame(storageAPI0.getClient(), storageAPI1.getClient());
+ assertSame(storageAPI0.getClient(), storageAPI2.getClient());
+ assertSame(storageAPI0.getClient(), storageAPI3.getClient());
+ assertSame(storageAPI0.getClient(), storageAPI4.getClient());
+ }
+
+ @Test
+ public void dynamicCreatedFirst() {
+ MongoDBBaSyxStorageAPI storageAPI0 = new MongoDBBaSyxStorageAPIFactory(config, VABTestType.class, "c0").create();
+ MongoDBBaSyxStorageAPI storageAPI1 = new MongoDBBaSyxStorageAPIFactory(config, VABTestType.class, "c1", client).create();
+
+ assertSame(storageAPI0.getClient(), storageAPI1.getClient());
+ }
+
+}
diff --git a/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/support/configuration/DummyBaSyxConfiguration.java b/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/support/configuration/DummyBaSyxConfiguration.java
index 3621ff3c..6030ac7b 100644
--- a/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/support/configuration/DummyBaSyxConfiguration.java
+++ b/basyx.components/basyx.components.lib/src/test/java/org/eclipse/basyx/regression/support/configuration/DummyBaSyxConfiguration.java
@@ -1,5 +1,6 @@
package org.eclipse.basyx.regression.support.configuration;
+import java.util.Collections;
import java.util.HashMap;
import org.eclipse.basyx.components.configuration.BaSyxConfiguration;
@@ -19,7 +20,7 @@ public class DummyBaSyxConfiguration extends BaSyxConfiguration {
public static final String AASX_UPLOAD = "aas.aasxUpload";
public DummyBaSyxConfiguration() {
- super(new HashMap