blob: 2e4b21e3ed4f5f64efa19a7fd91b62b375e8a993 [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.vab.modelprovider.generic;
import java.util.function.Function;
import org.eclipse.basyx.vab.exception.provider.NotAnInvokableException;
import org.eclipse.basyx.vab.exception.provider.ResourceAlreadyExistsException;
import org.eclipse.basyx.vab.exception.provider.ResourceNotFoundException;
import org.eclipse.basyx.vab.modelprovider.VABPathTools;
import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
/**
* A generic VAB model provider.
*
* @author espen
*/
public class VABModelProvider implements IModelProvider {
/**
* Handler, which handles single element objects
*/
private IVABElementHandler handler;
/**
* Root object that stores contained elements
*/
protected Object elements;
public VABModelProvider(Object elements, IVABElementHandler handler) {
this.handler = handler;
this.elements = elements;
}
@Override
public Object getModelPropertyValue(String path) {
Object element = getTargetElement(path);
return handler.postprocessObject(element);
}
@Override
public void setModelPropertyValue(String path, Object newValue) {
VABPathTools.checkPathForNull(path);
if (VABPathTools.isEmptyPath(path)) {
// Empty path => parent element == null => replace root, if it exists
if (elements != null) {
elements = newValue;
}
return;
}
Object parentElement = getParentElement(path);
String propertyName = VABPathTools.getLastElement(path);
// Throws an exception, if the element does not exist
handler.getElementProperty(parentElement, propertyName);
// => Can only set elements that have already been created
handler.setModelPropertyValue(parentElement, propertyName, newValue);
}
@Override
public void createValue(String path, Object newValue) {
VABPathTools.checkPathForNull(path);
if (VABPathTools.isEmptyPath(path)) {
// The complete model should be replaced if it does not exist
if (elements == null) {
elements = newValue;
} else {
throw new ResourceAlreadyExistsException("Root element does already exist.");
}
return;
}
// Find parent & name of new element
Object parentElement = getParentElement(path);
String propertyName = VABPathTools.getLastElement(path);
try {
Object childElement = handler.getElementProperty(parentElement, propertyName);
// The last path element does exist -> create the new value here
handler.createValue(childElement, newValue);
} catch (ResourceNotFoundException e) {
// The last path element does not exist
// -> create the new property in the parent element
handler.setModelPropertyValue(parentElement, propertyName, newValue);
}
}
@Override
public void deleteValue(String path) {
VABPathTools.checkPathForNull(path);
Object parentElement = getParentElement(path);
String propertyName = VABPathTools.getLastElement(path);
handler.deleteValue(parentElement, propertyName);
}
@Override
public void deleteValue(String path, Object obj) {
Object targetElement = getTargetElement(path);
handler.deleteValue(targetElement, obj);
}
@SuppressWarnings("unchecked")
@Override
public Object invokeOperation(String path, Object... parameters) {
path = VABPathTools.stripInvokeFromPath(path);
Object childElement = getModelPropertyValue(path);
// Invoke operation for function interfaces
if (childElement instanceof Function<?, ?>) {
Function<Object[], Object> function = (Function<Object[], Object>) childElement;
return function.apply(parameters);
} else {
throw new NotAnInvokableException("Element \"" + path + "\" is not a function.");
}
}
/**
* Get the parent of an element in this provider. The path should include the path to the element separated by '/'.
* E.g., for accessing element c in path a/b, the path should be a/b/c.
*/
private Object getParentElement(String path) {
VABPathTools.checkPathForNull(path);
// Split path into its elements, separated by '/'
String[] pathElements = VABPathTools.splitPath(path);
Object currentElement = elements;
// ignore the leaf element, only return the leaf's parent element
for (int i = 0; i < pathElements.length - 1; i++) {
currentElement = handler.getElementProperty(currentElement, pathElements[i]);
}
if (currentElement == null) {
throw new ResourceNotFoundException("Parent element for \"" + path + "\" does not exist.");
}
return currentElement;
}
/**
* Instead of returning the parent element of a path, this function gives the target element.
* E.g., it returns c for the path a/b/c
*/
protected Object getTargetElement(String path) {
VABPathTools.checkPathForNull(path);
if (VABPathTools.isEmptyPath(path)) {
return elements;
}
Object parentElement = getParentElement(path);
String operationName = VABPathTools.getLastElement(path);
if (operationName != null) {
return handler.getElementProperty(parentElement, operationName);
}
return null;
}
}