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

Use correct reference when adding thumbnail images #263

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 @@ -50,6 +50,7 @@ public class AASXSerializer {
private static final String MIME_PLAINTXT = "text/plain";
private static final String MIME_XML = "application/xml";

public static final String OPC_NAMESPACE = "http://schemas.openxmlformats.org/package/2006/relationships";
public static final String AASX_NAMESPACE = "http://admin-shell.io/aasx/relationships";

public static final String ORIGIN_RELTYPE = AASX_NAMESPACE + "/aasx-origin";
Expand All @@ -61,6 +62,8 @@ public class AASXSerializer {

public static final String AASSUPPL_RELTYPE = AASX_NAMESPACE + "/aas-suppl";

public static final String AAS_THUMBNAIL_RELTYPE = OPC_NAMESPACE + "/metadata/thumbnail";

private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

private final XmlSerializer xmlSerializer;
Expand All @@ -74,7 +77,7 @@ public AASXSerializer() {

/**
* Constructor with a custom serializer for serializing the aas environment
*
*
* @param xmlSerializer a custom serializer used for serializing the aas environment
*/
public AASXSerializer(XmlSerializer xmlSerializer) {
Expand All @@ -83,7 +86,7 @@ public AASXSerializer(XmlSerializer xmlSerializer) {

/**
* Generates the .aasx file and writes it to the given OutputStream
*
*
* @param environment the aas environment that will be included in the aasx package as an xml serialization
* @param files related inMemory files that belong to the given aas environment
* @param os an output stream for writing the aasx package
Expand All @@ -106,29 +109,29 @@ public void write(Environment environment, Collection<InMemoryFile> files, Outpu
// Save the XML to aasx/xml/content.xml
PackagePart xmlPart = createAASXPart(rootPackage, origin, XML_PATH, MIME_XML, AASSPEC_RELTYPE, xml.getBytes(DEFAULT_CHARSET));

environment.getAssetAdministrationShells().stream().filter(aas -> aas.getAssetInformation() != null
&& aas.getAssetInformation().getDefaultThumbnail() != null
&& aas.getAssetInformation().getDefaultThumbnail().getPath() != null)
.forEach(aas -> createParts(files,
AASXUtils.removeFilePartOfURI(aas.getAssetInformation().getDefaultThumbnail().getPath()),
rootPackage, rootPackage, aas.getAssetInformation().getDefaultThumbnail().getContentType(), AAS_THUMBNAIL_RELTYPE));
storeFilesInAASX(environment, files, rootPackage, xmlPart);

saveAASX(os, rootPackage);
}

/**
* Stores the files from the Submodels in the .aasx file
*
*
* @param environment the Environment
* @param files the content of the files
* @param rootPackage the OPCPackage
* @param xmlPart the Part the files should be related to
*/
private void storeFilesInAASX(Environment environment, Collection<InMemoryFile> files, OPCPackage rootPackage,
PackagePart xmlPart) {
environment.getAssetAdministrationShells().stream().filter(aas -> aas.getAssetInformation() != null
&& aas.getAssetInformation().getDefaultThumbnail() != null
&& aas.getAssetInformation().getDefaultThumbnail().getPath() != null)
.forEach(aas -> createParts(files,
AASXUtils.removeFilePartOfURI(aas.getAssetInformation().getDefaultThumbnail().getPath()),
rootPackage, xmlPart, aas.getAssetInformation().getDefaultThumbnail().getContentType()));
findFileElements(environment).forEach(file -> createParts(files,
AASXUtils.removeFilePartOfURI(file.getValue()), rootPackage, xmlPart, file.getContentType()));
AASXUtils.removeFilePartOfURI(file.getValue()), rootPackage, xmlPart, file.getContentType(), AASSUPPL_RELTYPE));
}

/**
Expand All @@ -139,13 +142,14 @@ private void storeFilesInAASX(Environment environment, Collection<InMemoryFile>
* @param rootPackage the OPCPackage
* @param xmlPart the Part the files should be related to
* @param contentType the contentType of the file
* @param relType the relationship type
*/
private void createParts(Collection<InMemoryFile> files, String filePath, OPCPackage rootPackage,
PackagePart xmlPart, String contentType) {
RelationshipSource xmlPart, String contentType, String relType) {
try {
InMemoryFile content = findFileByPath(files, filePath);
logger.trace("Writing file '{}' to .aasx.", filePath);
createAASXPart(rootPackage, xmlPart, filePath, contentType, AASSUPPL_RELTYPE, content.getFileContent());
createAASXPart(rootPackage, xmlPart, filePath, contentType, relType, content.getFileContent());
} catch (RuntimeException e) {
// Log that a file is missing and continue building the .aasx
logger.warn("Could not add File '{}'. It was not contained in given InMemoryFiles.", filePath, e);
Expand All @@ -154,7 +158,7 @@ private void createParts(Collection<InMemoryFile> files, String filePath, OPCPac

/**
* Saves the OPCPackage to the given OutputStream
*
*
* @param os the Stream to be saved to
* @param rootPackage the Package to be saved
* @throws IOException if creating output streams for aasx fails
Expand All @@ -167,7 +171,7 @@ private void saveAASX(OutputStream os, OPCPackage rootPackage) throws IOExceptio
/**
* Generates a UUID. Every element of the .aasx needs a unique Id according to
* the specification
*
*
* @return UUID
*/
private String createUniqueID() {
Expand All @@ -177,7 +181,7 @@ private String createUniqueID() {

/**
* Creates a Part (a file in the .aasx) of the .aasx and adds it to the Package
*
*
* @param root the OPCPackage
* @param relateTo the Part of the OPC the relationship of the new Part should be added to
* @param path the path inside the .aasx where the new Part should be created
Expand Down Expand Up @@ -209,7 +213,7 @@ private PackagePart createAASXPart(OPCPackage root, RelationshipSource relateTo,

/**
* Writes the content of a byte[] to a Part
*
*
* @param part the Part to be written to
* @param content the content to be written to the part
*/
Expand All @@ -225,7 +229,7 @@ private void writeDataToPart(PackagePart part, byte[] content) {
/**
* Gets the File elements from an environment
* searches in SubmodelElementCollections
*
*
* @param environment the Environment
* @return the found Files
*/
Expand All @@ -244,7 +248,7 @@ public void visit(File file) {

/**
* Replaces the path in all File Elements with the result of preparePath
*
*
* @param environment the Environment
*/
private void prepareFilePaths(Environment environment) {
Expand All @@ -253,7 +257,7 @@ private void prepareFilePaths(Environment environment) {

/**
* Finds an InMemoryFile by its path
*
*
* @param files the InMemoryFiles
* @param path the path of the wanted file
* @return the InMemoryFile if it was found; else null
Expand All @@ -269,7 +273,7 @@ private InMemoryFile findFileByPath(Collection<InMemoryFile> files, String path)

/**
* Removes the serverpart from a path and ensures it starts with "file://"
*
*
* @param path the path to be prepared
* @return the prepared path
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

Expand All @@ -38,6 +40,7 @@

public class AASXSerializerTest {

private static final String RELS_PATH_URI = "file:///_rels/.rels";
private static final String XML_PATH_URI = "file:///aasx/xml/content.xml";
private static final String ORIGIN_PATH_URI = "file:///aasx/aasx-origin";

Expand All @@ -56,7 +59,7 @@ public void testBuildAASXFull() throws IOException, TransformerException, Parser

new AASXSerializer().write(AASFull.createEnvironment(), fileList, out);

validateAASX(out);
validateAASX(out, List.of(AASXSerializerTest::assertRootXml));
}

@Test
Expand All @@ -75,28 +78,26 @@ public void testBuildAASXSimple() throws IOException, TransformerException, Pars

new AASXSerializer().write(AASSimple.createEnvironment(), fileList, out);

validateAASX(out);
validateAASX(out, List.of(AASXSerializerTest::assertRootXml, AASXSerializerTest::assertThumbnailReference));
}

private void validateAASX(ByteArrayOutputStream byteStream) throws IOException {
private void validateAASX(ByteArrayOutputStream byteStream, List<BiConsumer<ZipEntry, ZipInputStream>> fileValidators) {
ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(byteStream.toByteArray()));
ZipEntry zipEntry = null;
ZipEntry zipEntry;

ArrayList<String> filePaths = new ArrayList<>();

while ((zipEntry = in.getNextEntry()) != null) {
if (zipEntry.getName().equals(XML_PATH_URI)) {

// Read the first 5 bytes of the XML file to make sure it is in fact XML file
// No further test of XML file necessary as XML-Converter is tested separately
byte[] buf = new byte[5];
in.read(buf);
assertEquals("<?xml", new String(buf));
try {
while ((zipEntry = in.getNextEntry()) != null) {
for (final BiConsumer<ZipEntry, ZipInputStream> validator : fileValidators) {
validator.accept(zipEntry, in);
}

// Write the paths of all files contained in the .aasx into filePaths
filePaths.add("file:///" + zipEntry.getName());
}

// Write the paths of all files contained in the .aasx into filePaths
filePaths.add("file:///" + zipEntry.getName());
} catch (IOException e) {
throw new RuntimeException(e);
}

assertTrue(filePaths.contains(XML_PATH_URI));
Expand All @@ -110,4 +111,33 @@ private void validateAASX(ByteArrayOutputStream byteStream) throws IOException {
}

}

private static void assertRootXml(ZipEntry zipEntry, ZipInputStream in) {
if (!XML_PATH_URI.endsWith(zipEntry.getName())) {
return;
}
// Read the first 5 bytes of the XML file to make sure it is in fact XML file
// No further test of XML file necessary as XML-Converter is tested separately
byte[] buf = new byte[5];
try {
in.read(buf);
} catch (IOException e) {
throw new RuntimeException(e);
}
assertEquals("<?xml", new String(buf));
}

private static void assertThumbnailReference(ZipEntry zipEntry, ZipInputStream in) {
if (!RELS_PATH_URI.endsWith(zipEntry.getName())) {
return;
}
final String content;
try {
content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException(e);
}
assertTrue(content.contains("Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\""));
assertTrue(content.contains("Target=\"master/verwaltungsschale-detail-part1.png\""));
}
}