Skip to content

Commit

Permalink
Refactors Converters under usage of AasEnv (#7)
Browse files Browse the repository at this point in the history
* Refactor Converters to use AasEnv

Signed-off-by: Jannis Jung <[email protected]>
  • Loading branch information
jannisjung authored Oct 27, 2021
1 parent 134017e commit 03fa7ef
Show file tree
Hide file tree
Showing 8 changed files with 404 additions and 214 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.eclipse.basyx.aas.bundle.AASBundle;
import org.eclipse.basyx.aas.bundle.AASBundleFactory;
import org.eclipse.basyx.aas.factory.xml.XMLToMetamodelConverter;
import org.eclipse.basyx.aas.metamodel.map.AasEnv;
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;
Expand Down Expand Up @@ -68,6 +69,8 @@ public class AASXToMetamodelConverter {

private Set<AASBundle> bundles;

private AasEnv aasEnv;

private static Logger logger = LoggerFactory.getLogger(AASXToMetamodelConverter.class);

public AASXToMetamodelConverter(String path) {
Expand All @@ -78,6 +81,20 @@ public AASXToMetamodelConverter(InputStream stream) {
this.aasxInputStream = stream;
}

public AasEnv retrieveAasEnv()
throws ParserConfigurationException, SAXException, IOException, InvalidFormatException {
if (aasEnv != null) {
return aasEnv;
}

loadAASX();

String xmlContent = getXMLResourceString(aasxRoot);
XMLToMetamodelConverter converter = new XMLToMetamodelConverter(xmlContent);
closeOPCPackage();
return converter.parseAasEnv();
}

@SuppressWarnings("unchecked")
public <T extends AASBundle> Set<T> retrieveAASBundles() throws IOException, ParserConfigurationException, SAXException, InvalidFormatException {

Expand All @@ -88,10 +105,10 @@ public <T extends AASBundle> Set<T> retrieveAASBundles() throws IOException, Par

loadAASX();

String xmlContent = getXMLResourceString(aasxRoot);
XMLToMetamodelConverter converter = new XMLToMetamodelConverter(xmlContent);
AasEnv localAasEnv = retrieveAasEnv();

bundles = new AASBundleFactory().create(converter.parseAAS(), converter.parseSubmodels(), converter.parseAssets());
bundles = new AASBundleFactory().create(localAasEnv.getAssetAdministrationShells(), localAasEnv.getSubmodels(),
localAasEnv.getAssets());

closeOPCPackage();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.eclipse.basyx.aas.factory.xml.MetamodelToXMLConverter;
import org.eclipse.basyx.aas.metamodel.api.IAssetAdministrationShell;
import org.eclipse.basyx.aas.metamodel.api.parts.asset.IAsset;
import org.eclipse.basyx.aas.metamodel.map.AasEnv;
import org.eclipse.basyx.submodel.metamodel.api.ISubmodel;
import org.eclipse.basyx.submodel.metamodel.api.parts.IConceptDescription;
import org.eclipse.basyx.submodel.metamodel.api.submodelelement.ISubmodelElement;
Expand Down Expand Up @@ -73,12 +74,14 @@ public class MetamodelToAASXConverter {
/**
* Generates the .aasx file and writes it to the given OutputStream
*
* @param aasList the AASs to be saved in the .aasx
* @param assetList the Assets to be saved in the .aasx
* @param conceptDescriptionList the ConceptDescriptions to be saved in the .aasx
* @param submodelList the Submodels to be saved in the .aasx
* @param files the files referred to in the Submodels
* @param os the OutputStream the resulting .aasx is written to
* @param aasList the AASs to be saved in the .aasx
* @param assetList the Assets to be saved in the .aasx
* @param conceptDescriptionList the ConceptDescriptions to be saved in the
* .aasx
* @param submodelList the Submodels to be saved in the .aasx
* @param files the files referred to in the Submodels
* @param os the OutputStream the resulting .aasx is written
* to
* @throws IOException
* @throws TransformerException
* @throws ParserConfigurationException
Expand All @@ -90,20 +93,33 @@ public static void buildAASX(Collection<IAssetAdministrationShell> aasList, Coll

OPCPackage rootPackage = OPCPackage.create(os);

// Create the empty aasx-origin file
PackagePart origin = createAASXPart(rootPackage, rootPackage, ORIGIN_PATH, MIME_PLAINTXT, ORIGIN_RELTYPE, ORIGIN_CONTENT.getBytes());

// Convert the given Metamodels to XML
String xml = convertToXML(aasList, assetList, conceptDescriptionList, submodelList);

// Save the XML to aasx/xml/content.xml
PackagePart xmlPart = createAASXPart(rootPackage, origin, XML_PATH, MIME_XML, AASSPEC_RELTYPE, xml.getBytes());

storeFilesInAASX(submodelList, files, rootPackage, xmlPart);

saveAASX(os, rootPackage);
}

/**
* Generates the .aasx file and writes it to the given OutputStream
*
* @param aasEnv
* @param files
* @param os the OutputStream the resulting .aasx is written to
* @throws IOException
* @throws TransformerException
* @throws ParserConfigurationException
*/
public static void buildAASX(AasEnv aasEnv, Collection<InMemoryFile> files, OutputStream os)
throws IOException, TransformerException, ParserConfigurationException {
buildAASX(aasEnv.getAssetAdministrationShells(), aasEnv.getAssets(), aasEnv.getConceptDescriptions(),
aasEnv.getSubmodels(), files, os);
}

/**
* Stores the files from the Submodels in the .aasx file
*
Expand All @@ -118,17 +134,31 @@ private static void storeFilesInAASX(Collection<ISubmodel> submodelList, Collect
for(ISubmodel sm: submodelList) {
for(File file: findFileElements(sm.getSubmodelElements().values())) {
String filePath = file.getValue();
try {
InMemoryFile content = findFileByPath(files, filePath);
logger.trace("Writing file '" + filePath + "' to .aasx.");
createAASXPart(rootPackage, xmlPart, filePath, file.getMimeType(), AASSUPPL_RELTYPE, content.getFileContent());
} catch (ResourceNotFoundException e) {
// Log that a file is missing and continue building the .aasx
logger.warn("Could not add File '" + filePath + "'. It was not contained in given InMemoryFiles.");
}
storeFileInAASX(files, rootPackage, xmlPart, file, filePath);
}
}
}

/**
* Stores a single file in the .aasx file
*
* @param files
* @param rootPackage
* @param xmlPart
* @param file
* @param filePath
*/
private static void storeFileInAASX(Collection<InMemoryFile> files, OPCPackage rootPackage, PackagePart xmlPart,
File file, String filePath) {
try {
InMemoryFile content = findFileByPath(files, filePath);
logger.trace("Writing file '" + filePath + "' to .aasx.");
createAASXPart(rootPackage, xmlPart, filePath, file.getMimeType(), AASSUPPL_RELTYPE, content.getFileContent());
} catch (ResourceNotFoundException e) {
// Log that a file is missing and continue building the .aasx
logger.warn("Could not add File '" + filePath + "'. It was not contained in given InMemoryFiles.");
}
}

/**
* Saves the OPCPackage to the given OutputStream
Expand Down Expand Up @@ -262,17 +292,14 @@ private static void prepareFilePaths(Collection<ISubmodel> submodels, Collection
}

/**
* Removes the serverpart from a path and ensures it starts with a slash
* Removes the serverpart from a path. VABPathTools.getPathFromURL() also
* ensures that it starts with a slash.
*
* @param path the path to be prepared
* @return the prepared path
*/
private static String preparePath(String path) {
String newPath = VABPathTools.getPathFromURL(path);
if(!newPath.startsWith("/")) {
newPath = "/" + newPath;
}
return newPath;
return VABPathTools.getPathFromURL(path);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@
******************************************************************************/
package org.eclipse.basyx.aas.factory.json;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.eclipse.basyx.aas.metamodel.api.IAssetAdministrationShell;
import org.eclipse.basyx.aas.metamodel.api.parts.asset.IAsset;
import org.eclipse.basyx.aas.metamodel.map.AasEnv;
import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;
import org.eclipse.basyx.aas.metamodel.map.parts.Asset;
import org.eclipse.basyx.submodel.metamodel.api.ISubmodel;
import org.eclipse.basyx.submodel.metamodel.api.parts.IConceptDescription;
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;
Expand All @@ -26,56 +32,119 @@
/**
* This class can be used to parse JSON to Metamodel Objects
*
* @author conradi
* @author conradi, jungjan
*
*/
public class JSONToMetamodelConverter {

private Map<String, Object> root;

// Buffer used for parsed assets to prevent deserializing them multiple times
private List<Asset> assetBuf;
private AasEnv aasEnv;

@SuppressWarnings("unchecked")
/**
* Initializes the parser with XML given as a String
*
* @param jsonContent the JSON content to be parsed
*/
public JSONToMetamodelConverter(String jsonContent) {
root = (Map<String, Object>) new GSONTools(new DefaultTypeFactory()).deserialize(jsonContent);
Map<String, Object> root = createRoot(jsonContent);

List<IAsset> assets = createAssets(root);

List<IAssetAdministrationShell> shells = createShells(root, assets);

List<IConceptDescription> conceptDescriptions = createConceptDescriptions(root);

List<ISubmodel> submodels = createSubmodels(root);

aasEnv = new AasEnv(shells, assets, conceptDescriptions, submodels);
}

@SuppressWarnings("unchecked")
private List<ISubmodel> createSubmodels(Map<String, Object> root) {
return ((List<Object>) root.get(MetamodelToJSONConverter.SUBMODELS)).stream()
.map(smMap -> Submodel.createAsFacade((Map<String, Object>) smMap)).collect(Collectors.toList());
}

@SuppressWarnings("unchecked")
private List<IConceptDescription> createConceptDescriptions(Map<String, Object> root) {
return ((List<Object>) root
.get(MetamodelToJSONConverter.CONCEPT_DESCRIPTIONS)).stream()
.map(cdMap -> ConceptDescription.createAsFacade((Map<String, Object>) cdMap))
.collect(Collectors.toList());
}

@SuppressWarnings("unchecked")
private List<IAssetAdministrationShell> createShells(Map<String, Object> root, List<IAsset> assets) {
return ((List<Object>) root
.get(MetamodelToJSONConverter.ASSET_ADMINISTRATION_SHELLS)).stream()
.map(aasObject -> handleJSONAssetReference(aasObject, (List<Asset>) (List<?>) assets))
.collect(Collectors.toList());
}

@SuppressWarnings("unchecked")
private List<IAsset> createAssets(Map<String, Object> root) {
return ((List<Object>) root.get(MetamodelToJSONConverter.ASSETS)).stream()
.map(aMap -> Asset.createAsFacade((Map<String, Object>) aMap)).collect(Collectors.toList());
}

@SuppressWarnings("unchecked")
private Map<String, Object> createRoot(String jsonContent) {
return (Map<String, Object>) new GSONTools(new DefaultTypeFactory())
.deserialize(jsonContent);
}

/**
* Parses the AasEnv from the JSON
*
* @return the AasEnv parsed from the JSON
*/
public AasEnv parseAasEnv() {
return aasEnv;
}

/**
* Parses the AASs from the JSON
*
* @return the AASs parsed from the JSON
*/
@SuppressWarnings("unchecked")
public List<AssetAdministrationShell> parseAAS() {
assetBuf = parseAssets();
return ((List<Object>) root.get(MetamodelToJSONConverter.ASSET_ADMINISTRATION_SHELLS)).stream()
.map(this::parseAssetAdministrationShell).collect(Collectors.toList());
return new ArrayList<>((List<AssetAdministrationShell>) (List<?>) aasEnv.getAssetAdministrationShells());
}

@SuppressWarnings("unchecked")
private AssetAdministrationShell parseAssetAdministrationShell(Object mapObject) {
Map<String, Object> aasMap = (Map<String, Object>) mapObject;
// Fix Asset - Asset in json-Serialization is just a reference
private AssetAdministrationShell handleJSONAssetReference(Object aasObject, List<Asset> assets) {
Map<String, Object> aasMap = (Map<String, Object>) aasObject;
Map<String, Object> assetRefMap = (Map<String, Object>) aasMap.get(AssetAdministrationShell.ASSET);
if (assetRefMap.get(Reference.KEY) == null && assetRefMap.get(Asset.KIND) != null) {
// => Is already an asset, => does not need to be fixed
return AssetAdministrationShell.createAsFacade((Map<String, Object>) mapObject);

if (isAssetReference(assetRefMap)) {
return handleReference(aasObject, aasMap, assetRefMap, assets);
} else {
return AssetAdministrationShell.createAsFacade((Map<String, Object>) aasObject);
}

}

@SuppressWarnings("unchecked")
private AssetAdministrationShell handleReference(Object aasObject, Map<String, Object> aasMap,
Map<String, Object> assetRefMap, List<Asset> assets) {
aasMap.put(AssetAdministrationShell.ASSETREF, assetRefMap);

// Now try to find the Asset and add it to the AssetAdministrationShell
IReference assetRef = Reference.createAsFacade((Map<String, Object>) aasMap.get(AssetAdministrationShell.ASSETREF));
IReference assetRef = Reference
.createAsFacade((Map<String, Object>) aasMap.get(AssetAdministrationShell.ASSETREF));
IKey lastKey = assetRef.getKeys().get(assetRef.getKeys().size() - 1);
String idValue = lastKey.getValue();
for (Asset asset : assetBuf) {
for (Asset asset : assets) {
if (asset.getIdentification().getId().equals(idValue)) {
aasMap.put(AssetAdministrationShell.ASSET, asset);
break;
}
}

return AssetAdministrationShell.createAsFacade((Map<String, Object>) mapObject);
return AssetAdministrationShell.createAsFacade((Map<String, Object>) aasObject);
}

private boolean isAssetReference(Map<String, Object> assetRefMap) {
return assetRefMap.get(Reference.KEY) != null && assetRefMap.get(Asset.KIND) == null;
}

/**
Expand All @@ -85,8 +154,7 @@ private AssetAdministrationShell parseAssetAdministrationShell(Object mapObject)
*/
@SuppressWarnings("unchecked")
public List<Submodel> parseSubmodels() {
return ((List<Object>) root.get(MetamodelToJSONConverter.SUBMODELS)).stream()
.map(i -> Submodel.createAsFacade((Map<String, Object>) i)).collect(Collectors.toList());
return new ArrayList<>((List<Submodel>) (List<?>) aasEnv.getSubmodels());
}

/**
Expand All @@ -96,8 +164,7 @@ public List<Submodel> parseSubmodels() {
*/
@SuppressWarnings("unchecked")
public List<Asset> parseAssets() {
return ((List<Object>) root.get(MetamodelToJSONConverter.ASSETS)).stream()
.map(i -> Asset.createAsFacade((Map<String, Object>) i)).collect(Collectors.toList());
return new ArrayList<>((List<Asset>) (List<?>) aasEnv.getAssets());
}

/**
Expand All @@ -107,7 +174,6 @@ public List<Asset> parseAssets() {
*/
@SuppressWarnings("unchecked")
public List<ConceptDescription> parseConceptDescriptions() {
return ((List<Object>) root.get(MetamodelToJSONConverter.CONCEPT_DESCRIPTIONS)).stream()
.map(i -> ConceptDescription.createAsFacade((Map<String, Object>) i)).collect(Collectors.toList());
return new ArrayList<>((List<ConceptDescription>) (List<?>) aasEnv.getConceptDescriptions());
}
}
Loading

0 comments on commit 03fa7ef

Please sign in to comment.