From 03fa7efeedcc29223dc5c62eb041f03191461c47 Mon Sep 17 00:00:00 2001 From: jannisjung <92165516+jannisjung@users.noreply.github.com> Date: Wed, 27 Oct 2021 07:44:32 +0200 Subject: [PATCH] Refactors Converters under usage of AasEnv (#7) * Refactor Converters to use AasEnv Signed-off-by: Jannis Jung --- .../aasx/AASXToMetamodelConverter.java | 23 ++- .../aasx/MetamodelToAASXConverter.java | 73 +++++--- .../json/JSONToMetamodelConverter.java | 118 +++++++++--- .../json/MetamodelToJSONConverter.java | 44 +++-- .../factory/xml/MetamodelToXMLConverter.java | 35 +++- .../factory/xml/XMLToMetamodelConverter.java | 73 +++++--- .../AssetAdministrationShellXMLConverter.java | 170 ++++++++++-------- .../parts/ConceptDescriptionXMLConverter.java | 82 +++++---- 8 files changed, 404 insertions(+), 214 deletions(-) diff --git a/src/main/java/org/eclipse/basyx/aas/factory/aasx/AASXToMetamodelConverter.java b/src/main/java/org/eclipse/basyx/aas/factory/aasx/AASXToMetamodelConverter.java index 8fa5c344..a3be83ec 100644 --- a/src/main/java/org/eclipse/basyx/aas/factory/aasx/AASXToMetamodelConverter.java +++ b/src/main/java/org/eclipse/basyx/aas/factory/aasx/AASXToMetamodelConverter.java @@ -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; @@ -68,6 +69,8 @@ public class AASXToMetamodelConverter { private Set bundles; + private AasEnv aasEnv; + private static Logger logger = LoggerFactory.getLogger(AASXToMetamodelConverter.class); public AASXToMetamodelConverter(String path) { @@ -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 Set retrieveAASBundles() throws IOException, ParserConfigurationException, SAXException, InvalidFormatException { @@ -88,10 +105,10 @@ public Set 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(); diff --git a/src/main/java/org/eclipse/basyx/aas/factory/aasx/MetamodelToAASXConverter.java b/src/main/java/org/eclipse/basyx/aas/factory/aasx/MetamodelToAASXConverter.java index 6271ff83..4e361c8a 100644 --- a/src/main/java/org/eclipse/basyx/aas/factory/aasx/MetamodelToAASXConverter.java +++ b/src/main/java/org/eclipse/basyx/aas/factory/aasx/MetamodelToAASXConverter.java @@ -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; @@ -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 @@ -90,13 +93,10 @@ public static void buildAASX(Collection 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); @@ -104,6 +104,22 @@ public static void buildAASX(Collection aasList, Coll 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 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 * @@ -118,17 +134,31 @@ private static void storeFilesInAASX(Collection 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 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 @@ -262,17 +292,14 @@ private static void prepareFilePaths(Collection 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); } /** diff --git a/src/main/java/org/eclipse/basyx/aas/factory/json/JSONToMetamodelConverter.java b/src/main/java/org/eclipse/basyx/aas/factory/json/JSONToMetamodelConverter.java index 6bc11e9c..670e9244 100644 --- a/src/main/java/org/eclipse/basyx/aas/factory/json/JSONToMetamodelConverter.java +++ b/src/main/java/org/eclipse/basyx/aas/factory/json/JSONToMetamodelConverter.java @@ -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; @@ -26,21 +32,75 @@ /** * This class can be used to parse JSON to Metamodel Objects * - * @author conradi + * @author conradi, jungjan * */ public class JSONToMetamodelConverter { - private Map root; - - // Buffer used for parsed assets to prevent deserializing them multiple times - private List 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) new GSONTools(new DefaultTypeFactory()).deserialize(jsonContent); + Map root = createRoot(jsonContent); + + List assets = createAssets(root); + + List shells = createShells(root, assets); + + List conceptDescriptions = createConceptDescriptions(root); + + List submodels = createSubmodels(root); + + aasEnv = new AasEnv(shells, assets, conceptDescriptions, submodels); + } + + @SuppressWarnings("unchecked") + private List createSubmodels(Map root) { + return ((List) root.get(MetamodelToJSONConverter.SUBMODELS)).stream() + .map(smMap -> Submodel.createAsFacade((Map) smMap)).collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + private List createConceptDescriptions(Map root) { + return ((List) root + .get(MetamodelToJSONConverter.CONCEPT_DESCRIPTIONS)).stream() + .map(cdMap -> ConceptDescription.createAsFacade((Map) cdMap)) + .collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + private List createShells(Map root, List assets) { + return ((List) root + .get(MetamodelToJSONConverter.ASSET_ADMINISTRATION_SHELLS)).stream() + .map(aasObject -> handleJSONAssetReference(aasObject, (List) (List) assets)) + .collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + private List createAssets(Map root) { + return ((List) root.get(MetamodelToJSONConverter.ASSETS)).stream() + .map(aMap -> Asset.createAsFacade((Map) aMap)).collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + private Map createRoot(String jsonContent) { + return (Map) 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 * @@ -48,34 +108,43 @@ public JSONToMetamodelConverter(String jsonContent) { */ @SuppressWarnings("unchecked") public List parseAAS() { - assetBuf = parseAssets(); - return ((List) root.get(MetamodelToJSONConverter.ASSET_ADMINISTRATION_SHELLS)).stream() - .map(this::parseAssetAdministrationShell).collect(Collectors.toList()); + return new ArrayList<>((List) (List) aasEnv.getAssetAdministrationShells()); } @SuppressWarnings("unchecked") - private AssetAdministrationShell parseAssetAdministrationShell(Object mapObject) { - Map aasMap = (Map) mapObject; - // Fix Asset - Asset in json-Serialization is just a reference + private AssetAdministrationShell handleJSONAssetReference(Object aasObject, List assets) { + Map aasMap = (Map) aasObject; Map assetRefMap = (Map) 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) mapObject); + + if (isAssetReference(assetRefMap)) { + return handleReference(aasObject, aasMap, assetRefMap, assets); + } else { + return AssetAdministrationShell.createAsFacade((Map) aasObject); } + + } + + @SuppressWarnings("unchecked") + private AssetAdministrationShell handleReference(Object aasObject, Map aasMap, + Map assetRefMap, List assets) { aasMap.put(AssetAdministrationShell.ASSETREF, assetRefMap); - // Now try to find the Asset and add it to the AssetAdministrationShell - IReference assetRef = Reference.createAsFacade((Map) aasMap.get(AssetAdministrationShell.ASSETREF)); + IReference assetRef = Reference + .createAsFacade((Map) 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) mapObject); + return AssetAdministrationShell.createAsFacade((Map) aasObject); + } + + private boolean isAssetReference(Map assetRefMap) { + return assetRefMap.get(Reference.KEY) != null && assetRefMap.get(Asset.KIND) == null; } /** @@ -85,8 +154,7 @@ private AssetAdministrationShell parseAssetAdministrationShell(Object mapObject) */ @SuppressWarnings("unchecked") public List parseSubmodels() { - return ((List) root.get(MetamodelToJSONConverter.SUBMODELS)).stream() - .map(i -> Submodel.createAsFacade((Map) i)).collect(Collectors.toList()); + return new ArrayList<>((List) (List) aasEnv.getSubmodels()); } /** @@ -96,8 +164,7 @@ public List parseSubmodels() { */ @SuppressWarnings("unchecked") public List parseAssets() { - return ((List) root.get(MetamodelToJSONConverter.ASSETS)).stream() - .map(i -> Asset.createAsFacade((Map) i)).collect(Collectors.toList()); + return new ArrayList<>((List) (List) aasEnv.getAssets()); } /** @@ -107,7 +174,6 @@ public List parseAssets() { */ @SuppressWarnings("unchecked") public List parseConceptDescriptions() { - return ((List) root.get(MetamodelToJSONConverter.CONCEPT_DESCRIPTIONS)).stream() - .map(i -> ConceptDescription.createAsFacade((Map) i)).collect(Collectors.toList()); + return new ArrayList<>((List) (List) aasEnv.getConceptDescriptions()); } } diff --git a/src/main/java/org/eclipse/basyx/aas/factory/json/MetamodelToJSONConverter.java b/src/main/java/org/eclipse/basyx/aas/factory/json/MetamodelToJSONConverter.java index 80a9afb1..1bf9d5aa 100644 --- a/src/main/java/org/eclipse/basyx/aas/factory/json/MetamodelToJSONConverter.java +++ b/src/main/java/org/eclipse/basyx/aas/factory/json/MetamodelToJSONConverter.java @@ -11,11 +11,13 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +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.facade.SubmodelElementMapCollectionConverter; @@ -37,6 +39,20 @@ public class MetamodelToJSONConverter { public static final String ASSETS = "assets"; public static final String CONCEPT_DESCRIPTIONS = "conceptDescriptions"; + /** + * Builds the JSON for the aasEnv + * + * @param aasEnv + * @return + */ + @SuppressWarnings("unchecked") + public static String convertToJSON(AasEnv aasEnv) { + return convertToJSON((List) (List) aasEnv.getAssetAdministrationShells(), + (List) (List) aasEnv.getAssets(), + (List) (List) aasEnv.getConceptDescriptions(), + (List) (List) aasEnv.getSubmodels()); + } + /** * Builds the JSON for the given metamodel Objects. * Not required parameters can be null. @@ -46,28 +62,28 @@ public class MetamodelToJSONConverter { * @param conceptDescriptionList the ConceptDescriptions to build the JSON for * @param submodelList the Submodels to build the JSON for */ - public static String convertToJSON(Collection aasList, Collection assetList, + public static String convertToJSON(Collection aasList, Collection assetList, Collection conceptDescriptionList, Collection submodelList) { - // The Submodel-Object holds SubmodelElements in a Map - // The JSON-Schema requires the SubmodelElements to be in a List - // This conversion is done by converting the sm to a Map - List smMapList; - if(submodelList != null) { - smMapList = submodelList.stream() - .map(sm -> SubmodelElementMapCollectionConverter.smToMap(sm)).collect(Collectors.toList()); - } else { - smMapList = new ArrayList<>(); - } - + List smMapList = submodelsToMapList(submodelList); Map root = new HashMap<>(); - root.put(ASSET_ADMINISTRATION_SHELLS, aasList==null ? new ArrayList() : aasList); + root.put(ASSET_ADMINISTRATION_SHELLS, aasList == null ? new ArrayList() : aasList); root.put(SUBMODELS, smMapList); root.put(ASSETS, assetList==null ? new ArrayList() : assetList); - root.put(CONCEPT_DESCRIPTIONS, conceptDescriptionList==null ? new ArrayList() : conceptDescriptionList); + root.put(CONCEPT_DESCRIPTIONS, + conceptDescriptionList == null ? new ArrayList() : conceptDescriptionList); return new GSONTools(new DefaultTypeFactory()).serialize(root); + } + + private static List submodelsToMapList(Collection submodelList) { + if (submodelList != null) { + return submodelList.stream().map(sm -> SubmodelElementMapCollectionConverter.smToMap(sm)) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } } } diff --git a/src/main/java/org/eclipse/basyx/aas/factory/xml/MetamodelToXMLConverter.java b/src/main/java/org/eclipse/basyx/aas/factory/xml/MetamodelToXMLConverter.java index 40ce6df2..00189824 100644 --- a/src/main/java/org/eclipse/basyx/aas/factory/xml/MetamodelToXMLConverter.java +++ b/src/main/java/org/eclipse/basyx/aas/factory/xml/MetamodelToXMLConverter.java @@ -25,6 +25,7 @@ import org.eclipse.basyx.aas.factory.xml.converters.AssetAdministrationShellXMLConverter; 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.factory.xml.api.parts.ConceptDescriptionXMLConverter; import org.eclipse.basyx.submodel.factory.xml.converters.SubmodelXMLConverter; import org.eclipse.basyx.submodel.metamodel.api.ISubmodel; @@ -41,14 +42,29 @@ public class MetamodelToXMLConverter { public static final String AASENV = "aas:aasenv"; + /** + * Builds the XML for the given aasEnv + * + * @param aasEnv + * @param result a Result object to write the XML to e.g. ResultStream + * @throws TransformerException + * @throws ParserConfigurationException + */ + public static void convertToXML(AasEnv aasEnv, Result result) + throws TransformerException, ParserConfigurationException { + convertToXML(aasEnv.getAssetAdministrationShells(), aasEnv.getAssets(), aasEnv.getConceptDescriptions(), + aasEnv.getSubmodels(), result); + } + /** * Builds the XML for the given metamodel Objects * - * @param aasList the AASs to build the XML for - * @param assetList the Assets to build the XML for + * @param aasList the AASs to build the XML for + * @param assetList the Assets to build the XML for * @param conceptDescriptionList the ConceptDescriptions to build the XML for - * @param submodelList the Submodels to build the XML for - * @param result a Result object to write the XML to e.g. ResultStream + * @param submodelList the Submodels to build the XML for + * @param result a Result object to write the XML to e.g. + * ResultStream * @throws TransformerException * @throws ParserConfigurationException */ @@ -56,9 +72,7 @@ public static void convertToXML(Collection aasList, C Collection conceptDescriptionList, Collection submodelList, Result result) throws TransformerException, ParserConfigurationException { - DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder(); - Document document = documentBuilder.newDocument(); + Document document = createEmptyDocument(); //creating the root tag Element root = document.createElement(AASENV); @@ -95,4 +109,11 @@ public static void convertToXML(Collection aasList, C transformer.transform(domSource, result); } + + private static Document createEmptyDocument() throws ParserConfigurationException { + DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder(); + Document document = documentBuilder.newDocument(); + return document; + } } diff --git a/src/main/java/org/eclipse/basyx/aas/factory/xml/XMLToMetamodelConverter.java b/src/main/java/org/eclipse/basyx/aas/factory/xml/XMLToMetamodelConverter.java index a6621498..b95cd2c2 100644 --- a/src/main/java/org/eclipse/basyx/aas/factory/xml/XMLToMetamodelConverter.java +++ b/src/main/java/org/eclipse/basyx/aas/factory/xml/XMLToMetamodelConverter.java @@ -10,6 +10,7 @@ package org.eclipse.basyx.aas.factory.xml; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -20,6 +21,7 @@ import org.eclipse.basyx.aas.factory.xml.converters.AssetAdministrationShellXMLConverter; 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.factory.xml.api.parts.ConceptDescriptionXMLConverter; import org.eclipse.basyx.submodel.factory.xml.converters.SubmodelXMLConverter; import org.eclipse.basyx.submodel.metamodel.api.ISubmodel; @@ -34,9 +36,9 @@ * */ public class XMLToMetamodelConverter { - - private Map root = new HashMap<>(); + private AasEnv aasEnv; + /** * Initializes the Parser with XML given as a String * @@ -47,68 +49,83 @@ public class XMLToMetamodelConverter { * @throws IOException */ @SuppressWarnings("unchecked") - public XMLToMetamodelConverter(String xmlContent) throws ParserConfigurationException, SAXException, IOException { + public XMLToMetamodelConverter(String xmlContent) throws ParserConfigurationException, SAXException, IOException { + Map root = new HashMap<>(); root.putAll((Map) XmlParser.buildXmlMap(xmlContent) .get(MetamodelToXMLConverter.AASENV)); + + Map xmlAASs = (Map) root + .get(AssetAdministrationShellXMLConverter.ASSET_ADMINISTRATION_SHELLS); + + Map xmlConceptDescriptions = (Map) root + .get(ConceptDescriptionXMLConverter.CONCEPT_DESCRIPTIONS); + + List conceptDescriptions = ConceptDescriptionXMLConverter + .parseConceptDescriptions(xmlConceptDescriptions); + + List shells = AssetAdministrationShellXMLConverter + .parseAssetAdministrationShells(xmlAASs, conceptDescriptions); + + Map xmlSubmodels = (Map) root.get(SubmodelXMLConverter.SUBMODELS); + List submodels = SubmodelXMLConverter.parseSubmodels(xmlSubmodels); + Map xmlAssets = (Map) root.get(AssetXMLConverter.ASSETS); + List assets = AssetXMLConverter.parseAssets(xmlAssets); + + aasEnv = new AasEnv(shells, assets, conceptDescriptions, submodels); } + /** + * Parses the AasEnv from the XML + * + * @return the AasEnv parsed from the XML + */ + public AasEnv parseAasEnv() { + return aasEnv; + } /** - * Parses the AASs form the XML + * Parses the AASs from the XML * - * @return the AASs parsed form the XML + * @return the AASs parsed from the XML * @throws ParserConfigurationException * @throws SAXException * @throws IOException */ - @SuppressWarnings("unchecked") public List parseAAS() throws ParserConfigurationException, SAXException, IOException { - Map xmlAASs = (Map) root - .get(AssetAdministrationShellXMLConverter.ASSET_ADMINISTRATION_SHELLS); - // First, parse all conceptDescriptions - List conceptDescriptions = parseConceptDescriptions(); - // Then parse the AAS -> the available conceptDescriptions have to be mapped to the contained concept - // dictionaries - return AssetAdministrationShellXMLConverter.parseAssetAdministrationShells(xmlAASs, conceptDescriptions); + return new ArrayList<>(aasEnv.getAssetAdministrationShells()); } /** - * Parses the Assets form the XML + * Parses the Assets from the XML * - * @return the Assets parsed form the XML + * @return the Assets parsed from the XML * @throws ParserConfigurationException * @throws SAXException * @throws IOException */ - @SuppressWarnings("unchecked") public List parseAssets() throws ParserConfigurationException, SAXException, IOException { - Map xmlAssets = (Map) root.get(AssetXMLConverter.ASSETS); - return AssetXMLConverter.parseAssets(xmlAssets); + return new ArrayList<>(aasEnv.getAssets()); } /** - * Parses the Submodels form the XML + * Parses the Submodels from the XML * - * @return the Submodels parsed form the XML + * @return the Submodels parsed from the XML */ - @SuppressWarnings("unchecked") public List parseSubmodels() { - Map xmlSubmodels = (Map) root.get(SubmodelXMLConverter.SUBMODELS); - return SubmodelXMLConverter.parseSubmodels(xmlSubmodels); + return new ArrayList<>(aasEnv.getSubmodels()); } /** - * Parses the ConceptDescriptions form the XML + * Parses the ConceptDescriptions from the XML * - * @return the ConceptDescriptions parsed form the XML + * @return the ConceptDescriptions parsed from the XML */ - @SuppressWarnings("unchecked") public List parseConceptDescriptions() { - Map xmlConceptDescriptions = (Map) root.get(ConceptDescriptionXMLConverter.CONCEPT_DESCRIPTIONS); - return ConceptDescriptionXMLConverter.parseConceptDescriptions(xmlConceptDescriptions); + return new ArrayList<>(aasEnv.getConceptDescriptions()); } } diff --git a/src/main/java/org/eclipse/basyx/aas/factory/xml/converters/AssetAdministrationShellXMLConverter.java b/src/main/java/org/eclipse/basyx/aas/factory/xml/converters/AssetAdministrationShellXMLConverter.java index 7d95a57d..3a951665 100644 --- a/src/main/java/org/eclipse/basyx/aas/factory/xml/converters/AssetAdministrationShellXMLConverter.java +++ b/src/main/java/org/eclipse/basyx/aas/factory/xml/converters/AssetAdministrationShellXMLConverter.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -39,13 +40,14 @@ import org.w3c.dom.Element; /** - * Handles the conversion between IAssetAdministrationShell objects and the XML tag <aas:assetAdministrationShells> in both directions + * Handles the conversion between IAssetAdministrationShell objects and the XML + * tag <aas:assetAdministrationShells> in both directions * * @author conradi * */ public class AssetAdministrationShellXMLConverter { - + public static final String ASSET_ADMINISTRATION_SHELLS = "aas:assetAdministrationShells"; public static final String ASSET_ADMINISTRATION_SHELL = "aas:assetAdministrationShell"; public static final String DERIVED_FROM = "aas:derivedFrom"; @@ -56,61 +58,68 @@ public class AssetAdministrationShellXMLConverter { public static final String CONCEPT_DICTIONARY = "aas:conceptDictionary"; public static final String CONCEPT_DESCRIPTION_REFS = "aas:conceptDescriptionRefs"; public static final String CONCEPT_DESCRIPTION_REF = "aas:conceptDescriptionRef"; - - + /** - * Parses <aas:assetAdministrationShells> and builds the AssetAdministrationShell objects from it + * Parses <aas:assetAdministrationShells> and builds the + * AssetAdministrationShell objects from it * - * @param xmlAASObject a Map containing the content of the XML tag <aas:assetAdministrationShells> + * @param xmlAASObject a Map containing the content of the XML tag + * <aas:assetAdministrationShells> * @param conceptDescriptions the available concept descriptions - * @return a List of IAssetAdministrationShell objects parsed form the given XML Map + * @return a List of IAssetAdministrationShell objects parsed form the given XML + * Map */ @SuppressWarnings("unchecked") public static List parseAssetAdministrationShells(Map xmlAASObject, Collection conceptDescriptions) { - List> xmlAASs = XMLHelper.getList(xmlAASObject.get(ASSET_ADMINISTRATION_SHELL)); + if (xmlAASObject == null) { + return Collections.emptyList(); + } + List aasList = new ArrayList<>(); - - for(Map xmlAAS: xmlAASs) { + + List> xmlAASs = XMLHelper.getList(xmlAASObject.get(ASSET_ADMINISTRATION_SHELL)); + for (Map xmlAAS : xmlAASs) { AssetAdministrationShell adminShell = new AssetAdministrationShell(); - - IdentifiableXMLConverter.populateIdentifiable(xmlAAS, Identifiable.createAsFacadeNonStrict(adminShell, KeyElements.ASSETADMINISTRATIONSHELL)); - HasDataSpecificationXMLConverter.populateHasDataSpecification(xmlAAS, HasDataSpecification.createAsFacade(adminShell)); - + + IdentifiableXMLConverter.populateIdentifiable(xmlAAS, + Identifiable.createAsFacadeNonStrict(adminShell, KeyElements.ASSETADMINISTRATIONSHELL)); + HasDataSpecificationXMLConverter.populateHasDataSpecification(xmlAAS, + HasDataSpecification.createAsFacade(adminShell)); + Collection views = ViewXMLConverter.parseViews(xmlAAS); Collection conceptDictionary = parseConceptDictionaries(xmlAAS, conceptDescriptions); - + Map xmlAssetRef = (Map) xmlAAS.get(ASSET_REF); Reference assetRef = ReferenceXMLConverter.parseReference(xmlAssetRef); - + Map xmlDerivedFrom = (Map) xmlAAS.get(DERIVED_FROM); - IReference derivedFrom = ReferenceXMLConverter.parseReference(xmlDerivedFrom); + IReference derivedFrom = ReferenceXMLConverter.parseReference(xmlDerivedFrom); adminShell.setDerivedFrom(derivedFrom); - + adminShell.setViews(views); adminShell.setConceptDictionary(conceptDictionary); adminShell.setAssetReference(assetRef); - + Collection submodelRefs = parseSubmodelRefs(xmlAAS); adminShell.setSubmodelReferences(submodelRefs); - + aasList.add(adminShell); } + return aasList; } - - + /** * Parses <aas:submodelRefs> and builds {@link Reference} objects from it * - * @param xmlObject - * a Map containing the XML tag <aas:submodelRefs> + * @param xmlObject a Map containing the XML tag <aas:submodelRefs> * @return a Set of {@link IReference} objects parsed form the given XML Map */ @SuppressWarnings("unchecked") private static Collection parseSubmodelRefs(Map xmlObject) { Set refSet = new HashSet<>(); - + Map refMap = (Map) xmlObject.get(SUBMODEL_REFS); if (refMap == null) { @@ -121,15 +130,16 @@ private static Collection parseSubmodelRefs(Map xmlO for (Map xmlKey : xmlKeyList) { refSet.add(ReferenceXMLConverter.parseReference(xmlKey)); } - + return refSet; } - - + /** - * Parses <aas:conceptDictionaries> and builds IConceptDictionary objects from it + * Parses <aas:conceptDictionaries> and builds IConceptDictionary objects + * from it * - * @param xmlConceptDescriptionRefsObject a Map containing the XML tag <aas:conceptDictionaries> + * @param xmlConceptDescriptionRefsObject a Map containing the XML tag + * <aas:conceptDictionaries> * @param conceptDescriptions the available concept descriptions * @return a Set of IConceptDictionary objects parsed form the given XML Map */ @@ -137,32 +147,37 @@ private static Collection parseSubmodelRefs(Map xmlO private static Collection parseConceptDictionaries( Map xmlConceptDescriptionRefsObject, Collection conceptDescriptions) { Set conceptDictionarySet = new HashSet<>(); - if(xmlConceptDescriptionRefsObject == null) return conceptDictionarySet; - - Map xmlConceptDictionaries = (Map) xmlConceptDescriptionRefsObject.get(CONCEPT_DICTIONARIES); - if(xmlConceptDictionaries == null) return conceptDictionarySet; - - List> xmlConceptDictionaryList = XMLHelper.getList(xmlConceptDictionaries.get(CONCEPT_DICTIONARY)); + if (xmlConceptDescriptionRefsObject == null) + return conceptDictionarySet; + + Map xmlConceptDictionaries = (Map) xmlConceptDescriptionRefsObject + .get(CONCEPT_DICTIONARIES); + if (xmlConceptDictionaries == null) + return conceptDictionarySet; + + List> xmlConceptDictionaryList = XMLHelper + .getList(xmlConceptDictionaries.get(CONCEPT_DICTIONARY)); for (Map xmlConceptDictionary : xmlConceptDictionaryList) { ConceptDictionary conceptDictionary = new ConceptDictionary(); - ReferableXMLConverter.populateReferable(xmlConceptDictionary, Referable.createAsFacadeNonStrict(conceptDictionary, KeyElements.CONCEPTDICTIONARY)); - - Map xmlConceptDescriptionRefs = (Map) xmlConceptDictionary.get(CONCEPT_DESCRIPTION_REFS); + ReferableXMLConverter.populateReferable(xmlConceptDictionary, + Referable.createAsFacadeNonStrict(conceptDictionary, KeyElements.CONCEPTDICTIONARY)); + + Map xmlConceptDescriptionRefs = (Map) xmlConceptDictionary + .get(CONCEPT_DESCRIPTION_REFS); HashSet referenceSet = new HashSet<>(); - List> xmlConceptDescriptionRefsList = XMLHelper.getList(xmlConceptDescriptionRefs.get(CONCEPT_DESCRIPTION_REF)); + List> xmlConceptDescriptionRefsList = XMLHelper + .getList(xmlConceptDescriptionRefs.get(CONCEPT_DESCRIPTION_REF)); for (Map xmlConceptDescriptionRef : xmlConceptDescriptionRefsList) { referenceSet.add(ReferenceXMLConverter.parseReference(xmlConceptDescriptionRef)); } - + conceptDictionary.setConceptDescriptions(getConceptDescriptions(referenceSet, conceptDescriptions)); conceptDictionarySet.add(conceptDictionary); } - + return conceptDictionarySet; } - - - + /** * Gets concept descriptions according to given references * @@ -179,7 +194,7 @@ private static Collection getConceptDescriptions(Collection } IKey firstKey = ref.getKeys().iterator().next(); - if ( firstKey.getType() == KeyElements.CONCEPTDESCRIPTION && firstKey.isLocal() ) { + if (firstKey.getType() == KeyElements.CONCEPTDESCRIPTION && firstKey.isLocal()) { for (IConceptDescription description : conceptDescriptions) { if (description.getIdentification().getId().equals(firstKey.getValue())) { result.add(description); @@ -191,86 +206,86 @@ private static Collection getConceptDescriptions(Collection } /** - * Builds <aas:assetAdministrationShells> from a given Collection of IAssetAdministrationShell objects + * Builds <aas:assetAdministrationShells> from a given Collection of + * IAssetAdministrationShell objects * * @param document the XML document - * @param assetAdministrationShells a Collection of IAssetAdministrationShell objects to build the XML for - * @return the <aas:assetAdministrationShells> XML tag for the given IAssetAdministrationShell objects + * @param assetAdministrationShells a Collection of IAssetAdministrationShell + * objects to build the XML for + * @return the <aas:assetAdministrationShells> XML tag for the given + * IAssetAdministrationShell objects */ - public static Element buildAssetAdministrationShellsXML(Document document, Collection assetAdministrationShells) { + public static Element buildAssetAdministrationShellsXML(Document document, + Collection assetAdministrationShells) { Element root = document.createElement(ASSET_ADMINISTRATION_SHELLS); - + List xmlAASList = new ArrayList(); for (IAssetAdministrationShell aas : assetAdministrationShells) { Element aasRoot = document.createElement(ASSET_ADMINISTRATION_SHELL); IdentifiableXMLConverter.populateIdentifiableXML(document, aasRoot, aas); HasDataSpecificationXMLConverter.populateHasDataSpecificationXML(document, aasRoot, aas); - + buildDerivedFrom(document, aasRoot, aas); buildAssetRef(document, aasRoot, aas); buildSubmodelRef(document, aasRoot, aas); Collection views = aas.getViews(); - + Element buildViews = ViewXMLConverter.buildViewsXML(document, views); aasRoot.appendChild(buildViews); aasRoot.appendChild(buildConceptDictionary(document, aas)); xmlAASList.add(aasRoot); } - + for (Element element : xmlAASList) { root.appendChild(element); } return root; } - - + /** * Builds <aas:derivedFrom> from a given IAssetAdministrationShell object * * @param document the XML document - * @param root the XML tag to be populated - * @param aas the IAssetAdministrationShell object to build the XML for + * @param root the XML tag to be populated + * @param aas the IAssetAdministrationShell object to build the XML for */ private static void buildDerivedFrom(Document document, Element root, IAssetAdministrationShell aas) { IReference derivedFrom = aas.getDerivedFrom(); - if(derivedFrom != null) { + if (derivedFrom != null) { Element derivedFromRoot = document.createElement(DERIVED_FROM); - derivedFromRoot.appendChild(ReferenceXMLConverter.buildReferenceXML(document, derivedFrom)); + derivedFromRoot.appendChild(ReferenceXMLConverter.buildReferenceXML(document, derivedFrom)); root.appendChild(derivedFromRoot); } } - /** * Builds <aas:assetRef> from a given IAssetAdministrationShell object * * @param document the XML document - * @param root the XML tag to be populated - * @param aas the IAssetAdministrationShell object to build the XML for + * @param root the XML tag to be populated + * @param aas the IAssetAdministrationShell object to build the XML for */ private static void buildAssetRef(Document document, Element root, IAssetAdministrationShell aas) { IReference assetRef = aas.getAssetReference(); - if(assetRef!=null) { + if (assetRef != null) { Element assetrefRoot = document.createElement(ASSET_REF); assetrefRoot.appendChild(ReferenceXMLConverter.buildReferenceXML(document, assetRef)); root.appendChild(assetrefRoot); } } - /** * Builds <aas:submodelRefs> from a given IAssetAdministrationShell object * * @param document the XML document - * @param root the XML tag to be populated - * @param aas the IAssetAdministrationShell object to build the XML for + * @param root the XML tag to be populated + * @param aas the IAssetAdministrationShell object to build the XML for */ private static void buildSubmodelRef(Document document, Element root, IAssetAdministrationShell aas) { Collection submodelRef = aas.getSubmodelReferences(); - - + if (submodelRef != null && !submodelRef.isEmpty()) { Element submodelRefsRoot = document.createElement(SUBMODEL_REFS); for (IReference ref : submodelRef) { @@ -282,19 +297,20 @@ private static void buildSubmodelRef(Document document, Element root, IAssetAdmi root.appendChild(submodelRefsRoot); } } - /** - * Builds <aas:conceptDictionaries> from a given IAssetAdministrationShell object + * Builds <aas:conceptDictionaries> from a given IAssetAdministrationShell + * object * * @param document the XML document - * @param aas the IAssetAdministrationShell object to build the XML for - * @return the <aas:conceptDictionaries> XML tag build from the IAssetAdministrationShell object + * @param aas the IAssetAdministrationShell object to build the XML for + * @return the <aas:conceptDictionaries> XML tag build from the + * IAssetAdministrationShell object */ private static Element buildConceptDictionary(Document document, IAssetAdministrationShell aas) { Collection conceptDicionary = aas.getConceptDictionary(); Element conceptDicts = document.createElement(CONCEPT_DICTIONARIES); - for(IConceptDictionary iConceptDictionary: conceptDicionary) { + for (IConceptDictionary iConceptDictionary : conceptDicionary) { Element conceptDict = document.createElement(CONCEPT_DICTIONARY); Element concDescRoot = document.createElement(CONCEPT_DESCRIPTION_REFS); if (iConceptDictionary.getIdShort() != null) { @@ -305,14 +321,14 @@ private static Element buildConceptDictionary(Document document, IAssetAdministr conceptDict.appendChild(concDescRoot); conceptDicts.appendChild(conceptDict); Collection conceptDescriptionRef = iConceptDictionary.getConceptDescriptionReferences(); - for (IReference ref: conceptDescriptionRef) { - if(ref != null) { + for (IReference ref : conceptDescriptionRef) { + if (ref != null) { Element conceptDescriptionRefRoot = document.createElement(CONCEPT_DESCRIPTION_REF); concDescRoot.appendChild(conceptDescriptionRefRoot); conceptDescriptionRefRoot.appendChild(ReferenceXMLConverter.buildReferenceXML(document, ref)); } } - + } return conceptDicts; } diff --git a/src/main/java/org/eclipse/basyx/submodel/factory/xml/api/parts/ConceptDescriptionXMLConverter.java b/src/main/java/org/eclipse/basyx/submodel/factory/xml/api/parts/ConceptDescriptionXMLConverter.java index a46f9db9..c2849ba6 100644 --- a/src/main/java/org/eclipse/basyx/submodel/factory/xml/api/parts/ConceptDescriptionXMLConverter.java +++ b/src/main/java/org/eclipse/basyx/submodel/factory/xml/api/parts/ConceptDescriptionXMLConverter.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -30,7 +31,8 @@ import org.w3c.dom.Element; /** - * Handles the conversion between IConceptDescription objects and the XML tag <aas:conceptDescriptions> in both directions + * Handles the conversion between IConceptDescription objects and the XML tag + * <aas:conceptDescriptions> in both directions * * @author conradi * @@ -40,34 +42,39 @@ public class ConceptDescriptionXMLConverter { public static final String CONCEPT_DESCRIPTIONS = "aas:conceptDescriptions"; public static final String CONCEPT_DESCRIPTION = "aas:conceptDescription"; public static final String IS_CASE_OF = "aas:isCaseOf"; - - + /** - * Parses <aas:conceptDescriptions> and builds the IConceptDescription objects from it + * Parses <aas:conceptDescriptions> and builds the IConceptDescription + * objects from it * - * @param xmlObject a Map containing the content of the XML tag <aas:conceptDescriptions> + * @param xmlObject a Map containing the content of the XML tag + * <aas:conceptDescriptions> * @return a List of IConceptDescription objects parsed form the given XML Map */ public static List parseConceptDescriptions(Map xmlObject) { - - List> xmlConceptDescriptionList = XMLHelper.getList(xmlObject.get(CONCEPT_DESCRIPTION)); + if (xmlObject == null) { + return Collections.emptyList(); + } + List conceptDescriptions = new ArrayList<>(); - + List> xmlConceptDescriptionList = XMLHelper.getList(xmlObject.get(CONCEPT_DESCRIPTION)); + for (Map xmlConceptDescription : xmlConceptDescriptionList) { ConceptDescription conceptDescription = new ConceptDescription(); - - IdentifiableXMLConverter.populateIdentifiable(xmlConceptDescription, Identifiable.createAsFacadeNonStrict(conceptDescription, KeyElements.CONCEPTDESCRIPTION)); - HasDataSpecificationXMLConverter.populateHasDataSpecification(xmlConceptDescription, HasDataSpecification.createAsFacade(conceptDescription)); - + + IdentifiableXMLConverter.populateIdentifiable(xmlConceptDescription, + Identifiable.createAsFacadeNonStrict(conceptDescription, KeyElements.CONCEPTDESCRIPTION)); + HasDataSpecificationXMLConverter.populateHasDataSpecification(xmlConceptDescription, + HasDataSpecification.createAsFacade(conceptDescription)); + Collection handleIsCaseOf = parseIsCaseOfRefs(xmlConceptDescription); conceptDescription.setIsCaseOf(handleIsCaseOf); - + conceptDescriptions.add(conceptDescription); } - + return conceptDescriptions; } - /** * Parses <aas:isCaseOf> and builds a Reference object from it @@ -83,51 +90,54 @@ private static Collection parseIsCaseOfRefs(Map xmlOb } return references; } - - - - + /** - * Builds <aas:conceptDescriptions> from a given Collection of IConceptDescription objects + * Builds <aas:conceptDescriptions> from a given Collection of + * IConceptDescription objects * - * @param document the XML document - * @param conceptDescriptions a Collection of IConceptDescription objects to build the XML for - * @return the <aas:conceptDescriptions> XML tag for the given IConceptDescription objects + * @param document the XML document + * @param conceptDescriptions a Collection of IConceptDescription objects to + * build the XML for + * @return the <aas:conceptDescriptions> XML tag for the given + * IConceptDescription objects */ - public static Element buildConceptDescriptionsXML(Document document, Collection conceptDescriptions) { + public static Element buildConceptDescriptionsXML(Document document, + Collection conceptDescriptions) { Element root = document.createElement(CONCEPT_DESCRIPTIONS); - + List xmlConceptDescriptionList = new ArrayList(); - for(IConceptDescription conceptDescription: conceptDescriptions) { + for (IConceptDescription conceptDescription : conceptDescriptions) { Element conceptDescriptionRoot = document.createElement(CONCEPT_DESCRIPTION); IdentifiableXMLConverter.populateIdentifiableXML(document, conceptDescriptionRoot, conceptDescription); - HasDataSpecificationXMLConverter.populateHasDataSpecificationXML(document, conceptDescriptionRoot, conceptDescription); + HasDataSpecificationXMLConverter.populateHasDataSpecificationXML(document, conceptDescriptionRoot, + conceptDescription); buildIsCaseOf(document, conceptDescriptionRoot, conceptDescription); xmlConceptDescriptionList.add(conceptDescriptionRoot); - + } - - for(Element element: xmlConceptDescriptionList) { + + for (Element element : xmlConceptDescriptionList) { root.appendChild(element); } return root; } - - + /** * Builds <aas:isCaseOf> from a given IConceptDescription object * - * @param document the XML document + * @param document the XML document * @param xmlConceptDescription the XML tag to be populated - * @param conceptDescription the IConceptDescription object to build the XML for + * @param conceptDescription the IConceptDescription object to build the XML + * for */ - private static void buildIsCaseOf(Document document, Element xmlConceptDescription, IConceptDescription conceptDescription) { + private static void buildIsCaseOf(Document document, Element xmlConceptDescription, + IConceptDescription conceptDescription) { Collection references = conceptDescription.getIsCaseOf(); Element xmlIsCaseOf = document.createElement(IS_CASE_OF); Element keysElement = ReferenceXMLConverter.buildReferencesXML(document, references); - if(keysElement != null) { + if (keysElement != null) { xmlIsCaseOf.appendChild(keysElement); xmlConceptDescription.appendChild(xmlIsCaseOf); }