Skip to content

Commit

Permalink
Use correct reference when adding thumbnail images (#263)
Browse files Browse the repository at this point in the history
* Use correct reference when adding thumbnail images

fix #256

* Fix formatting

* Apply further formatting fixes
  • Loading branch information
andreas-schilling authored Mar 14, 2024
1 parent 24b4ba1 commit 429da95
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 35 deletions.
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\""));
}
}

0 comments on commit 429da95

Please sign in to comment.