blob: c41ce342a6d5bded1d3364619a1b9b1ec1888e66 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2021 the Eclipse BaSyx Authors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
******************************************************************************/
package org.eclipse.basyx.components.xml;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.basyx.aas.factory.xml.XMLToMetamodelConverter;
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.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.qualifier.IIdentifiable;
import org.eclipse.basyx.submodel.metamodel.api.reference.IKey;
import org.eclipse.basyx.submodel.metamodel.api.reference.IReference;
import org.eclipse.basyx.support.bundle.AASBundle;
import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
/**
* Creates multiple {@link AASBundle} from an XML containing several AAS and
* Submodels <br>
* TODO: ConceptDescriptions
*
* @author schnicke
*
*/
public class XMLAASBundleFactory {
private static Logger logger = LoggerFactory.getLogger(XMLAASBundleFactory.class);
private String content;
/**
*
* @param xmlContent
* the content of the XML
*/
public XMLAASBundleFactory(String xmlContent) {
this.content = xmlContent;
}
public XMLAASBundleFactory(Path xmlFile) throws IOException {
content = new String(Files.readAllBytes(xmlFile));
}
/**
* Creates the set of {@link AASBundle} contained in the XML string.
*
* @return
* @throws IOException
* @throws SAXException
* @throws ParserConfigurationException
*/
public Set<AASBundle> create() throws ParserConfigurationException, SAXException, IOException {
XMLToMetamodelConverter converter = new XMLToMetamodelConverter(content);
List<IAssetAdministrationShell> shells = converter.parseAAS();
List<ISubmodel> submodels = converter.parseSubmodels();
List<IAsset> assets = converter.parseAssets();
Set<AASBundle> bundles = new HashSet<>();
for (IAssetAdministrationShell shell : shells) {
// Retrieve asset
try {
IReference assetRef = shell.getAssetReference();
IAsset asset = getByReference(assetRef, assets);
((AssetAdministrationShell) shell).setAsset((Asset) asset);
} catch (ResourceNotFoundException e) {
logger.warn("Can't find asset with id " + shell.getAssetReference().getKeys().get(0).getValue() + " for AAS " + shell.getIdShort() + "; If the asset is not provided in another way, this is an error!");
}
// Retrieve submodels
Set<ISubmodel> currentSM = retrieveSubmodelsForAAS(submodels, shell);
bundles.add(new AASBundle(shell, currentSM));
}
return bundles;
}
/**
* Retrieves the Submodels belonging to an AAS
*
* @param submodels
* @param shell
* @return
*/
private Set<ISubmodel> retrieveSubmodelsForAAS(List<ISubmodel> submodels, IAssetAdministrationShell shell) {
Set<ISubmodel> currentSM = new HashSet<>();
for (IReference submodelRef : shell.getSubmodelReferences()) {
try {
ISubmodel sm = getByReference(submodelRef, submodels);
currentSM.add(sm);
logger.debug("Found Submodel " + sm.getIdShort() + " for AAS " + shell.getIdShort());
} catch (ResourceNotFoundException e) {
// If there's no match, the submodel is assumed to be provided by different
// means, e.g. it is already being hosted
logger.warn("Could not find Submodel " + submodelRef.getKeys().get(0).getValue() + " for AAS " + shell.getIdShort() + "; If it is not hosted elsewhere this is an error!");
}
}
return currentSM;
}
/**
* Retrieves an identifiable from a list of identifiable by its reference
*
* @param submodelRef
* @param submodels
* @return
* @throws ResourceNotFoundException
*/
private <T extends IIdentifiable> T getByReference(IReference ref, List<T> submodels) throws ResourceNotFoundException {
IKey lastKey = null;
// It may be that only one key fits to the Submodel contained in the XML
for (IKey key : ref.getKeys()) {
lastKey = key;
// There will only be a single submodel matching the identification at max
Optional<T> match = submodels.stream().filter(s -> s.getIdentification().getId().equals(key.getValue())).findFirst();
if (match.isPresent()) {
return match.get();
}
}
if (lastKey == null) {
throw new ResourceNotFoundException("Could not resolve reference without keys");
} else {
throw new ResourceNotFoundException("Could not resolve reference with last key " + lastKey.getValue());
}
// If no identifiable is found, indicate it by throwing an exception
}
}