blob: 133b0cba16bac1e14b9f3e98a1e606a1723e5901 [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.submodel.restapi;
import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.basyx.submodel.metamodel.facade.SubmodelElementMapCollectionConverter;
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.SubmodelElementCollection;
import org.eclipse.basyx.vab.exception.provider.MalformedRequestException;
import org.eclipse.basyx.vab.exception.provider.ProviderException;
import org.eclipse.basyx.vab.modelprovider.VABElementProxy;
import org.eclipse.basyx.vab.modelprovider.VABPathTools;
import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
/**
* Provider that handles container properties. Container properties can contain other submodel elements.
*
* @author espen, conradi
*
*/
public class MultiSubmodelElementProvider implements IModelProvider {
// Constants for API-Access
public static final String ELEMENTS = "submodelElements";
public static final String VALUE = "value";
// The VAB model provider containing the submodelElements this SubmodelElementProvider is based on
// Assumed to be a map that maps idShorts to the submodel elements
private IModelProvider modelProvider;
/**
* Constructor based on a model provider that contains the container property
*/
public MultiSubmodelElementProvider(IModelProvider provider) {
this.modelProvider = provider;
}
/**
* The elements are stored in a map => convert them to a list
*/
@SuppressWarnings("unchecked")
protected Collection<Map<String, Object>> getElementsList() {
Object elements = modelProvider.getModelPropertyValue("");
Map<String, Map<String, Object>> all = (Map<String, Map<String, Object>>) elements;
// Feed all ELements through their Providers, in case someting needs to be done to them (e.g. smElemCollections)
return all.entrySet().stream().map(e -> (Map<String, Object>) getSingleElement(ELEMENTS + "/" + e.getKey())).collect(Collectors.toList());
}
/**
* Single elements can be directly accessed in maps => return a proxy
*/
private IModelProvider getElementProxy(String[] pathElements) {
String idShort = pathElements[1];
return new VABElementProxy(idShort, modelProvider);
}
private Object getSingleElement(String path) {
// Build new proxy pointing at sub-property of a submodelelement and forward the
// remaininig part of the path to an appropriate provider
String[] pathElements = VABPathTools.splitPath(path);
String qualifier = pathElements[0];
IModelProvider elementProxy = getElementProxy(pathElements);
if (qualifier.equals(ELEMENTS)) {
String subPath = VABPathTools.buildPath(pathElements, 2);
return new SubmodelElementProvider(elementProxy).getModelPropertyValue(subPath);
} else {
throw new MalformedRequestException("Given path '" + path + "' does not start with /submodelElements");
}
}
@Override
public Object getModelPropertyValue(String path) throws ProviderException {
String[] pathElements = VABPathTools.splitPath(path);
String qualifier = pathElements[0];
if(!qualifier.equals(ELEMENTS)) {
// No other qualifier in a submodel element container can be directly accessed
throw new MalformedRequestException("Given path '" + path + "' does not start with /submodelElements");
}
if (pathElements.length == 1) {
// returns all elements
return getElementsList();
} else {
// The path requests a single Element
return getSingleElement(path);
}
}
@Override
public void setModelPropertyValue(String path, Object newValue) throws ProviderException {
String[] pathElements = VABPathTools.splitPath(path);
String qualifier = pathElements[0];
if (pathElements.length < 2 || !qualifier.equals(ELEMENTS)) {
// only possible to set values in a data elements, currently
throw new MalformedRequestException("Given path '" + path + "' is invalid for set");
}
IModelProvider elementProxy = getElementProxy(pathElements);
String subPath = VABPathTools.buildPath(pathElements, 2);
new SubmodelElementProvider(elementProxy).setModelPropertyValue(subPath, newValue);
}
@Override
@SuppressWarnings("unchecked")
public void createValue(String path, Object newEntity) throws ProviderException {
String[] pathElements = VABPathTools.splitPath(path);
String qualifier = pathElements[0];
String subPath = VABPathTools.buildPath(pathElements, 2);
if (!qualifier.equals(ELEMENTS)) {
throw new MalformedRequestException("Given path '" + path + "' does not start with /submodelElements");
}
// Check if the passed element is a SubmodelElementCollection. If yes, the value
// of the "value" key needs to be handled
if (SubmodelElementCollection.isSubmodelElementCollection((Map<String, Object>) newEntity)) {
SubmodelElementCollection smCollection = SubmodelElementCollection.createAsFacade((Map<String, Object>) newEntity);
newEntity = SubmodelElementMapCollectionConverter.mapToSmECollection(smCollection);
}
if (pathElements.length == 2) {
modelProvider.createValue(pathElements[1], newEntity);
} else {
IModelProvider elementProxy = getElementProxy(pathElements);
new SubmodelElementProvider(elementProxy).createValue(subPath, newEntity);
}
}
@Override
public void deleteValue(String path) throws ProviderException {
String[] pathElements = VABPathTools.splitPath(path);
String qualifier = pathElements[0];
String subPath;
IModelProvider elementProvider;
if (!qualifier.equals(ELEMENTS)) {
throw new MalformedRequestException("Given path '" + path + "' does not start with /submodelElements");
}
// If the first Element is a Collection, use its Provider
if(pathElements.length > 2) {
IModelProvider elementProxy = getElementProxy(pathElements);
elementProvider = new SubmodelElementProvider(elementProxy);
subPath = VABPathTools.buildPath(pathElements, 2);
} else {
elementProvider = modelProvider;
subPath = VABPathTools.buildPath(pathElements, 1);
}
// Delete a specific submodel element
elementProvider.deleteValue(subPath);
}
@Override
public void deleteValue(String path, Object obj) {
throw new MalformedRequestException("Delete with a passed argument not allowed");
}
@Override
public Object invokeOperation(String path, Object... parameters) throws ProviderException {
String[] pathElements = VABPathTools.splitPath(path);
String subPath = VABPathTools.buildPath(pathElements, 2);
String qualifier = pathElements[0];
if (!qualifier.equals(ELEMENTS)) {
throw new MalformedRequestException("Given path '" + path + "' does not start with /submodelElements");
}
IModelProvider elementProxy = getElementProxy(pathElements);
return new SubmodelElementProvider(elementProxy).invokeOperation(subPath, parameters);
}
}