blob: 7941a4d73b512aa887f3c30c32223d57425447f2 [file] [log] [blame]
/*********************************************************************************
* Copyright (c) 2020, 2021 Robert Bosch GmbH and others.
*
* 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
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
********************************************************************************
*/
package org.eclipse.app4mc.amalthea.converters097.impl;
import java.io.File;
import java.util.List;
import java.util.Map;
import org.eclipse.app4mc.amalthea.converters.common.ServiceConstants;
import org.eclipse.app4mc.amalthea.converters.common.base.ICache;
import org.eclipse.app4mc.amalthea.converters.common.base.IConverter;
import org.eclipse.app4mc.amalthea.converters.common.converter.AbstractConverter;
import org.eclipse.app4mc.amalthea.converters.common.utils.AmaltheaNamespaceRegistry;
import org.eclipse.app4mc.amalthea.converters.common.utils.HelperUtil;
import org.eclipse.app4mc.amalthea.converters.common.utils.ModelVersion;
import org.eclipse.app4mc.amalthea.converters097.utils.ComponentPortInterfaceCacheBuilder;
import org.eclipse.app4mc.util.sessionlog.SessionLogger;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
@Component(
property = {
ServiceConstants.INPUT_MODEL_VERSION_PROPERTY + "=0.9.6",
ServiceConstants.OUTPUT_MODEL_VERSION_PROPERTY + "=0.9.7"},
service = IConverter.class)
public class ComponentsModelConverter extends AbstractConverter {
@Reference
SessionLogger logger;
ComponentPortInterfaceCacheBuilder cache;
@Override
@Activate
protected void activate(Map<String, Object> properties) {
super.activate(properties);
}
@Override
public void convert(File targetFile, Map<File, Document> fileDocumentMapping, List<ICache> caches) {
logger.info("Migration from 0.9.6 to 0.9.7 : Executing ComponentsModel converter for model file : {0}", targetFile.getName());
this.cache = getComponentPortInterfaceCache(caches);
if (this.cache == null) {
throw new IllegalStateException("ComponentPortInterfaceCacheBuilder is not built and Object of it is not available in Converters");
}
basicConvert(targetFile, fileDocumentMapping);
}
/**
* This method is used to get the ComponentPortInterfaceCacheBuilder object
*
* @param caches The list of all caches.
* @return ComponentPortInterfaceCacheBuilder
*/
private ComponentPortInterfaceCacheBuilder getComponentPortInterfaceCache(List<ICache> caches) {
if (caches != null) {
for (ICache c : caches) {
if (c instanceof ComponentPortInterfaceCacheBuilder) {
return (ComponentPortInterfaceCacheBuilder) c;
}
}
}
return null;
}
private void basicConvert(File file, Map<File, Document> map) {
//get the components with interfaces
final Document document = map.get(file);
if (document == null) {
return;
}
final Element rootElement = document.getRootElement();
updateComponentTaskRefs(rootElement);
updateCallGraphs(rootElement);
updatePortInterfaceNames(rootElement,file);
updatePortReferences(rootElement);
updatePortComponentInstanceReferences(rootElement);
}
private void updateComponentTaskRefs(Element rootElement) {
final String xpathStr = "./componentsModel/components[@tasks]";
final List<Element> components = HelperUtil.getXpathResult(
rootElement,
xpathStr,
Element.class,
AmaltheaNamespaceRegistry.getNamespace(getOutputModelVersion(), "am"),
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
if (components == null) {
return;
}
for (Element component : components) {
Attribute attribute = component.getAttribute("tasks");
attribute.setName("processes");
}
}
private void updateCallGraphs(Element rootElement) {
final StringBuilder xpathBuilder = new StringBuilder();
xpathBuilder.append("./swModel/tasks/callGraph");
xpathBuilder.append("|");
xpathBuilder.append("./swModel/isrs/callGraph");
xpathBuilder.append("|");
xpathBuilder.append("./swModel/runnables/callGraph");
final List<Element> callGraphs = HelperUtil.getXpathResult(
rootElement,
xpathBuilder.toString(),
Element.class,
AmaltheaNamespaceRegistry.getNamespace(getOutputModelVersion(), "am"),
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element element : callGraphs) {
element.setName("activityGraph");
}
}
private void updatePortInterfaceNames(Element rootElement, File file) {
StringBuilder xpathStr = new StringBuilder();
xpathStr.append("./componentsModel/components/ports[@xsi:type=\"am:InterfacePort\"]");
final List<Element> componentPorts = HelperUtil.getXpathResult(
rootElement,
xpathStr.toString(),
Element.class,
AmaltheaNamespaceRegistry.getNamespace(ModelVersion._097, "am"),
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
boolean isLocal = cache.getCacheMap().containsKey(file);
if (isLocal) {
for (String interfaceName : this.cache.getCachedInterfaceNames()) {
createInterface(rootElement, interfaceName, file);
}
}
for (Element port : componentPorts) {
//update InterfacePort to ComponentPort
Attribute typeAttr = port.getAttribute("type", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
String typeValue = typeAttr.getValue();
typeValue = typeValue.replace("am:InterfacePort", "am:ComponentPort");
typeAttr.setValue(typeValue);
//create Interface
Attribute interfaceAttr = port.getAttribute("interfaceName");
if (interfaceAttr == null) {
continue;
}
//check if the interface is already created then create amlt ref
String value = interfaceAttr.getValue();
if (value == null || value.trim().isEmpty()) {
//remove the interfaceName attribute & move to next element in the loop
interfaceAttr.detach();
continue;
}
if (isLocal) {
interfaceAttr.setName("interface");
interfaceAttr.setValue(HelperUtil.encodeName(value)+"?type=MainInterface");
} else {
Element interfaceEle = new Element("interface");
interfaceEle.setAttribute("type", "am:MainInterface", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
interfaceEle.setAttribute("href", "amlt:/#" + (HelperUtil.encodeName(value)) + "?type=MainInterface");
port.addContent(interfaceEle);
interfaceAttr.detach();
}
//remove type interfacePort
typeAttr.detach();
}
}
private void createInterface(Element rootElement, String interfaceName, File file) {
String xpath = "./componentsModel";
List<Element> componentsModel = HelperUtil.getXpathResult(
rootElement,
xpath,
Element.class,
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
Element interfaceEle = new Element("interfaces");
interfaceEle.setAttribute("name", HelperUtil.encodeName(interfaceName));
if (!componentsModel.isEmpty()) {
componentsModel.get(0).addContent(interfaceEle);
} else {
Element componentsModelElement = new Element("componentsModel");
componentsModelElement.addContent(interfaceEle);
rootElement.addContent(componentsModelElement);
}
logger.info("Migration from 0.9.6 to 0.9.7 : Interface {0} created in File : {1}", interfaceName, file.getName());
}
private void updatePortReferences(Element rootElement) {
StringBuilder xPathStr = new StringBuilder();
xPathStr.append("./swModel/tasks/activityGraph/items[@port]");
xPathStr.append("|");
xPathStr.append("./swModel/isrs/activityGraph/items[@port]");
xPathStr.append("|");
xPathStr.append("./swModel/runnables/activityGraph/items[@port]");
xPathStr.append("|");
xPathStr.append("./swModel/tasks/activityGraph/items//items[@port]");
xPathStr.append("|");
xPathStr.append("./swModel/isrs/activityGraph/items//items[@port]");
xPathStr.append("|");
xPathStr.append("./swModel/runnables/activityGraph/items//items[@port]");
xPathStr.append("|");
xPathStr.append("./swModel/tasks/activityGraph/items//port[@xsi:type=\"am:InterfacePort\"]");
xPathStr.append("|");
xPathStr.append("./swModel/isrs/activityGraph/items//port[@xsi:type=\"am:InterfacePort\"]");
xPathStr.append("|");
xPathStr.append("./swModel/runnables/callGraph/items//port[@xsi:type=\"am:InterfacePort\"]");
xPathStr.append("|");
xPathStr.append("./componentsModel/systems/connectors//*[@port]");
xPathStr.append("|");
xPathStr.append("./componentsModel/systems/connectors//port[@xsi:type=\"am:InterfacePort\"]");
xPathStr.append("|");
xPathStr.append("./componentsModel/systems/groundedPorts");
xPathStr.append("|");
xPathStr.append("./componentsModel/components/connectors//*[@port]");
xPathStr.append("|");
xPathStr.append("./componentsModel/components/connectors//port[@xsi:type=\"am:InterfacePort\"]");
xPathStr.append("|");
xPathStr.append("./componentsModel/components/groundedPorts");
final List<Element> ports = HelperUtil.getXpathResult(
rootElement,
xPathStr.toString(),
Element.class,
AmaltheaNamespaceRegistry.getNamespace(ModelVersion._097, "am"),
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element element : ports) {
updatePortAttributes(element);
}
}
private void updatePortAttributes(Element element) {
Attribute port = element.getAttribute("port");
if (port == null ) {
port = element.getAttribute("href");
}
String value = port.getValue();
value = value.replace("?type=InterfacePort", "?type=ComponentPort");
port.setValue(value);
//remove type for href
Attribute type = element.getAttribute("type", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
if (type != null && type.getValue().equals("am:InterfacePort")) {
type.detach();
}
}
private void updatePortComponentInstanceReferences(Element rootElement) {
StringBuilder xPathStr = new StringBuilder();
xPathStr.append("./componentsModel/systems/connectors/sourcePort");
xPathStr.append("|");
xPathStr.append("./componentsModel/systems/connectors/targetPort");
xPathStr.append("|");
xPathStr.append("./componentsModel/systems/groundedPorts");
xPathStr.append("|");
xPathStr.append("./componentsModel/components/connectors/sourcePort");
xPathStr.append("|");
xPathStr.append("./componentsModel/components/connectors/targetPort");
xPathStr.append("|");
xPathStr.append("./componentsModel/components/groundedPorts");
Map<String, String> parentNames = cache.getCachedComponentInstanceParentNames();
final List<Element> qualifiedPorts = HelperUtil.getXpathResult(
rootElement,
xPathStr.toString(),
Element.class,
AmaltheaNamespaceRegistry.getNamespace(ModelVersion._097, "am"),
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element element : qualifiedPorts) {
Attribute instanceAttr = element.getAttribute("instance");
if (instanceAttr == null) {
Element hrefInstance = element.getChild("instance");
if (hrefInstance != null) {
logger.warn("Qualified Port is having a reference to component instance {0} from another model",
hrefInstance.getAttributeValue("href"));
}
continue;
}
String value = instanceAttr.getValue();
if (value.matches("(.*)\\?type=ComponentInstance")) {
String componentName = value.substring(0, value.indexOf("?type=ComponentInstance"));
String encodedParentName = parentNames.get(componentName);
if (encodedParentName != null) {
instanceAttr.setValue(encodedParentName + "/" + value);
}
}
}
}
}