Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix MongoDB Backend incorrectly saving files from loaded AASX #420

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -251,22 +251,12 @@ public void startComponent() {

loadAASServerFeaturesFromConfig();
initializeAASServerFeatures();

BaSyxContext context = contextConfig.createBaSyxContext();
context.addServletMapping("/*", createAggregatorServlet());
addAASServerFeaturesToContext(context);

// An initial AAS has been loaded from the drive?
if (aasBundles != null) {
createBasyxResourceDirectoryIfNotExists();

addAasxFilesResourceServlet(context);

// 2. Fix the file paths according to the servlet configuration
modifyFilePaths(contextConfig.getHostname(), contextConfig.getPort(), getRootFilePathWithContext(contextConfig.getContextPath()));
initializeAasBundles(context);

registerWhitelistedSubmodels();
}
context.addServletMapping("/*", createAggregatorServlet());
addAASServerFeaturesToContext(context);

logger.info("Start the server");
server = new BaSyxHTTPServer(context);
Expand Down Expand Up @@ -523,6 +513,24 @@ private void initializeAASServerFeatures() {
}
}

private void initializeAasBundles(BaSyxContext context) {
loadAASBundles();

if (aasBundles == null)
return;

logger.info("Initializing AAS Bundles");

createBasyxResourceDirectoryIfNotExists();

addAasxFilesResourceServlet(context);

// 2. Fix the file paths according to the servlet configuration
modifyFilePaths(contextConfig.getHostname(), contextConfig.getPort(), getRootFilePathWithContext(contextConfig.getContextPath()));

registerWhitelistedSubmodels();
}

private void cleanUpAASServerFeatures() {
for (IAASServerFeature aasServerFeature : aasServerFeatureList) {
aasServerFeature.cleanUp();
Expand Down Expand Up @@ -585,7 +593,6 @@ private Collection<AASBundle> getFlatAASBundles() {

private VABHTTPInterface<?> createAggregatorServlet() {
aggregator = createAASAggregator();
loadAASBundles();

if (aasBundles != null) {
try (final var ignored = ElevatedCodeAuthentication.enterElevatedCodeAuthenticationArea()) {
Expand Down Expand Up @@ -844,5 +851,6 @@ private void createBasyxResourceDirectoryIfNotExists() {

directory.mkdir();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,7 @@ public java.io.File getSubmodelElementFile(String idShortPath) {
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);
storageApi.writeFile(idShortPath, getSubmodel().getIdentification().getId(), fileStream, element);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
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 com.mongodb.client.MongoClient;
Expand Down Expand Up @@ -159,12 +158,12 @@ public ISubmodel getSubmodelbyIdShort(String idShort) throws ResourceNotFoundExc
@Override
public ISubmodelAPI getSubmodelAPIById(IIdentifier identifier) throws ResourceNotFoundException {
Submodel submodel = (Submodel) getSubmodel(identifier);
return new VABSubmodelAPIFactory().create(submodel);
return submodelApiFactory.create(submodel);
}

@Override
public ISubmodelAPI getSubmodelAPIByIdShort(String idShort) throws ResourceNotFoundException {
Submodel submodel = (Submodel) getSubmodelbyIdShort(idShort);
return new VABSubmodelAPIFactory().create(submodel);
return submodelApiFactory.create(submodel);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@
package org.eclipse.basyx.regression.AASServer;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
Expand All @@ -36,6 +41,14 @@
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.eclipse.basyx.aas.aggregator.restapi.AASAggregatorProvider;
import org.eclipse.basyx.aas.manager.ConnectedAssetAdministrationShellManager;
import org.eclipse.basyx.aas.metamodel.connected.ConnectedAssetAdministrationShell;
import org.eclipse.basyx.aas.metamodel.map.descriptor.AASDescriptor;
Expand All @@ -44,25 +57,28 @@
import org.eclipse.basyx.aas.metamodel.map.descriptor.SubmodelDescriptor;
import org.eclipse.basyx.aas.registration.api.IAASRegistry;
import org.eclipse.basyx.aas.registration.memory.InMemoryRegistry;
import org.eclipse.basyx.components.configuration.BaSyxContextConfiguration;
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.ISubmodelElementCollection;
import org.eclipse.basyx.submodel.metamodel.api.submodelelement.dataelement.IFile;
import org.eclipse.basyx.submodel.metamodel.connected.submodelelement.ConnectedSubmodelElementCollection;
import org.eclipse.basyx.submodel.metamodel.connected.submodelelement.dataelement.ConnectedFile;
import org.eclipse.basyx.vab.modelprovider.VABPathTools;
import org.eclipse.basyx.vab.protocol.api.IConnectorFactory;
import org.eclipse.basyx.vab.protocol.http.connector.HTTPConnectorFactory;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

/**
* Suite for testing that the XMLAAS servlet is set up correctly. The tests here
* can be used by the servlet test itself and the integration test
*
* @author schnicke, espen
* @author schnicke, espen, mateusmolina
*
*/
public abstract class AASXSuite {
Expand All @@ -86,6 +102,7 @@ public abstract class AASXSuite {
protected static final String fileShortIdPath = "file";

// Has to be individualized by each test inheriting from this suite
// Default configuration is provided by buildEnpoints method
protected static String aasEndpoint;
protected static String smEndpoint;
protected static String aasAEndpoint;
Expand Down Expand Up @@ -137,37 +154,26 @@ public void testGetSingleSubmodel() throws Exception {

@Test
public void testGetSingleModule() throws Exception {
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);
final String FILE_ENDING = VABPathTools.buildPath(new String[] { "basyx-temp", "aasx0", "files", "aasx", "Nameplate", "marking_rcm.jpg" }, 0);
checkFile(VABPathTools.concatenatePaths(rootEndpoint, FILE_ENDING));

// Get the submdoel nameplate
ISubmodel nameplate = manager.retrieveSubmodel(aasId, smId);
// Get the submodel element collection marking_rcm
ConnectedSubmodelElementCollection marking_rcm = (ConnectedSubmodelElementCollection) nameplate.getSubmodelElements().get("Marking_RCM");
Collection<ISubmodelElement> values = marking_rcm.getValue();

// navigate to the File element
Iterator<ISubmodelElement> iter = values.iterator();
while (iter.hasNext()) {
ISubmodelElement element = iter.next();
if (element instanceof ConnectedFile) {
ConnectedFile connectedFile = (ConnectedFile) element;
// get value of the file element
ConnectedFile fileSE = retrieveFileSEFromCollection(marking_rcm);

String fileurl = connectedFile.getValue();
assertTrue(fileurl.endsWith(FILE_ENDING));
}
}
assertTrue(fileSE.getValue().endsWith(FILE_ENDING));
}

@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";
final String FILE_ENDING_A = VABPathTools.buildPath(new String[] { "basyx-temp", "aasx1", "files", "aasx", "files", "text.txt" }, 0);
final String FILE_ENDING_B = VABPathTools.buildPath(new String[] { "basyx-temp", "aasx2", "files", "aasx", "files", "text.txt" }, 0);

checkFile(rootEndpoint + FILE_ENDING_A);
checkFile(rootEndpoint + FILE_ENDING_B);
checkFile(VABPathTools.concatenatePaths(rootEndpoint, FILE_ENDING_A));
checkFile(VABPathTools.concatenatePaths(rootEndpoint, FILE_ENDING_B));

ISubmodel smA = manager.retrieveSubmodel(aasAId, smAId);
ISubmodel smB = manager.retrieveSubmodel(aasBId, smBId);
Expand All @@ -194,6 +200,63 @@ public void testAllFiles() throws Exception {

}

@Test
public void fileValueIsCorrectlyUpdated_whenFileIsUpdated() throws Exception {
final String UPLOAD_ENDPOINT = VABPathTools.concatenatePaths(smEndpoint, "submodelElements", "Marking_CRUUS", "File", "upload");

ISubmodel nameplate = manager.retrieveSubmodel(aasId, smId);
ConnectedSubmodelElementCollection marking_cruus = (ConnectedSubmodelElementCollection) nameplate.getSubmodelElements().get("Marking_CRUUS");
ConnectedFile fileSE = retrieveFileSEFromCollection(marking_cruus);

String fileEndpointBefore = fileSE.getValue();
checkFile(fileEndpointBefore);

CloseableHttpResponse response = uploadDummyFileToSubmodelElement(UPLOAD_ENDPOINT, getFileFromResources("BaSyx.png"), ContentType.IMAGE_PNG);
try {
int statusCode = response.getStatusLine().getStatusCode();

assertEquals(HttpStatus.CREATED.value(), statusCode);

String fileEndpointAfter = fileSE.getValue();

assertNotEquals(fileEndpointBefore, fileEndpointAfter);
checkFile(fileEndpointAfter);

} finally {
response.close();
}
}

private ConnectedFile retrieveFileSEFromCollection(ConnectedSubmodelElementCollection marking_rcm) throws Exception {
Collection<ISubmodelElement> values = marking_rcm.getValue();

Iterator<ISubmodelElement> iter = values.iterator();
while (iter.hasNext()) {
ISubmodelElement element = iter.next();
if (element instanceof ConnectedFile) {
return (ConnectedFile) element;
}
}
throw new RuntimeException("No File SubmodelElement found in " + marking_rcm.getIdShort());
}

protected static void buildEndpoints(BaSyxContextConfiguration contextConfig) {
rootEndpoint = VABPathTools.stripSlashes(contextConfig.getUrl());

aasEndpoint = VABPathTools.concatenatePaths(rootEndpoint, AASAggregatorProvider.PREFIX, aasId.getEncodedURN(), "aas");
smEndpoint = VABPathTools.concatenatePaths(aasEndpoint, "submodels", smIdShort, "submodel");

String encodedAasAId = VABPathTools.encodePathElement(aasAId.getId());
aasAEndpoint = VABPathTools.concatenatePaths(rootEndpoint, AASAggregatorProvider.PREFIX, encodedAasAId, "aas");
smAEndpoint = VABPathTools.concatenatePaths(aasAEndpoint, "submodels", smAIdShort, "submodel");

String encodedAasBId = VABPathTools.encodePathElement(aasBId.getId());
aasBEndpoint = VABPathTools.concatenatePaths(rootEndpoint, AASAggregatorProvider.PREFIX, encodedAasBId, "aas");
smBEndpoint = VABPathTools.concatenatePaths(aasBEndpoint, "submodels", smBIdShort, "submodel");

logger.info("AAS URL for servlet test: " + aasEndpoint);
}

private void checkElementCollectionFiles(Collection<ISubmodelElement> elements) {
for (ISubmodelElement element : elements) {
if (element instanceof IFile) {
Expand Down Expand Up @@ -226,4 +289,23 @@ private void checkFile(String absolutePath) {
private ConnectedAssetAdministrationShell getConnectedAssetAdministrationShell() throws Exception {
return manager.retrieveAAS(aasId);
}

private File getFileFromResources(String filename) throws IOException, URISyntaxException {
URL resource = getClass().getClassLoader().getResource(filename);
if (resource == null)
throw new IllegalArgumentException("File not found!");

return new File(resource.toURI());

}

private CloseableHttpResponse uploadDummyFileToSubmodelElement(String endpoint, File file, ContentType contentType) throws IOException {
CloseableHttpClient client = HttpClients.createDefault();

HttpEntity fileEntity = MultipartEntityBuilder.create().addBinaryBody("file", file, contentType, file.getName()).build();
HttpPost postRequest = new HttpPost(endpoint);
postRequest.setEntity(fileEntity);

return client.execute(postRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,19 @@

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.file.Paths;

import javax.servlet.ServletException;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.FileUtils;
import org.eclipse.basyx.aas.aggregator.restapi.AASAggregatorProvider;
import org.eclipse.basyx.aas.factory.aasx.AASXToMetamodelConverter;
import org.eclipse.basyx.components.aas.AASServerComponent;
import org.eclipse.basyx.components.aas.configuration.AASServerBackend;
import org.eclipse.basyx.components.aas.configuration.BaSyxAASServerConfiguration;
import org.eclipse.basyx.components.configuration.BaSyxContextConfiguration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

/**
Expand All @@ -52,7 +48,6 @@
*
*/
public class TestAASXAASServer extends AASXSuite {
private static Logger logger = LoggerFactory.getLogger(TestAASXAASServer.class);
private static AASServerComponent component;

@BeforeClass
Expand All @@ -69,16 +64,7 @@ public static void setUpClass() throws ParserConfigurationException, SAXExceptio
component = new AASServerComponent(contextConfig, aasConfig);
component.startComponent();

rootEndpoint = contextConfig.getUrl() + "/";
aasEndpoint = rootEndpoint + "/" + AASAggregatorProvider.PREFIX + "/" + aasId.getEncodedURN() + "/aas";
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);
buildEndpoints(contextConfig);
}

@AfterClass
Expand Down
Loading