blob: 470f59c35fcf48fdd0783031b9996d11ed88fe6a [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2019, 2020 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.converters095.impl;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.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.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(
property = {
ServiceConstants.INPUT_MODEL_VERSION_PROPERTY + "=0.9.4",
ServiceConstants.OUTPUT_MODEL_VERSION_PROPERTY + "=0.9.5"
},
service = IConverter.class)
public class StimuliConverter extends AbstractConverter {
private static final Logger LOGGER = LoggerFactory.getLogger(StimuliConverter.class);
@Override
@Activate
protected void activate(Map<String, Object> properties) {
super.activate(properties);
}
@Override
public void convert(File targetFile, Map<File, Document> fileName_documentsMap, List<ICache> caches) {
LOGGER.info("Migration from 0.9.4 to 0.9.5 : Executing Stimuli converter for model file : {}", targetFile.getName());
basicConvert(targetFile, fileName_documentsMap);
}
public void basicConvert(final File file, final Map<File, Document> map) {
final Document document = map.get(file);
if (document == null) {
return;
}
final Element rootElement = document.getRootElement();
// migrate scenario
update_Scenario(rootElement);
// migrate clocks
update_ClocksMulitplierList(rootElement);
update_ClockSineFunction(rootElement);
update_ClockTriangleFunction(rootElement);
}
private void update_Scenario(Element rootElement) {
final String xpath = "./stimuliModel/stimuli[@xsi:type=\"am:VariableRateStimulus\"]/scenario";
final List<Element> scenarios = HelperUtil.getXpathResult(rootElement, xpath, Element.class,
AmaltheaNamespaceRegistry.getNamespace(ModelVersion._094, "am"),
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element element : scenarios) {
Element recurrence = element.getChild("recurrence");
if (recurrence != null) {
recurrence.detach();
String value = recurrence.getAttributeValue("value");
String unit = recurrence.getAttributeValue("unit");
addCustomProperty(element, "old_definition_v0.9.4", "recurrence=" + value + unit);
}
String clockAttribute = element.getAttributeValue("clock");
if (clockAttribute != null) {
Pattern p = Pattern.compile("(.+)\\?type=Clock(.+)");
Matcher m = p.matcher(clockAttribute);
if (m.find()) {
String clockRef = m.group(1);
String clockType = getNewClockType(m.group(2));
element.setAttribute("clock" , clockRef + "?type=Clock" + clockType);
}
}
Element clockElement = getSingleChild(element, "clock");
if (clockElement != null) {
String hrefValue = clockElement.getAttributeValue("href");
if (hrefValue != null) {
Pattern p = Pattern.compile("amlt:/#(.+)\\?type=Clock(.+)");
Matcher m = p.matcher(hrefValue);
if (m.find()) {
String clockRef = m.group(1);
String clockType = getNewClockType(m.group(2));
clockElement.setAttribute("type", "am:Clock" + clockType, AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
clockElement.setAttribute("href", "amlt:/#" + clockRef + "?type=Clock" + clockType);
}
}
}
}
}
private void update_ClockSineFunction(Element rootElement) {
final String xpath = "./stimuliModel/clocks[@xsi:type=\"am:ClockSinusFunction\"]";
final List<Element> clocks = HelperUtil.getXpathResult(rootElement, xpath, Element.class,
AmaltheaNamespaceRegistry.getNamespace(ModelVersion._094, "am"),
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
StringBuilder customPropsValue = new StringBuilder();
for (Element element : clocks) {
element.setAttribute("type", "am:ClockFunction", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
element.setAttribute("curveType", "sine");
Attribute amplitude = element.getAttribute("amplitude");
amplitude.detach();
customPropsValue.append(getStringValue(amplitude));
customPropsValue.append(" ");
Attribute offset = element.getAttribute("yOffset");
offset.detach();
customPropsValue.append(getStringValue(offset));
customPropsValue.append(" ");
customPropsValue.append(extractPeriodAndShift(element));
addCustomProperty(element, "old_definition_v0.9.4", customPropsValue.toString().trim());
}
}
private void update_ClockTriangleFunction(Element rootElement) {
final String xpath = "./stimuliModel/clocks[@xsi:type=\"am:ClockTriangleFunction\"]";
final List<Element> clocks = HelperUtil.getXpathResult(rootElement, xpath, Element.class,
AmaltheaNamespaceRegistry.getNamespace(ModelVersion._094, "am"),
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
StringBuilder customPropsValue = new StringBuilder();
for (Element element : clocks) {
element.setAttribute("type", "am:ClockFunction", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
element.setAttribute("curveType", "triangle");
Attribute max = element.getAttribute("max");
max.detach();
customPropsValue.append(getStringValue(max));
customPropsValue.append(" ");
Attribute min = element.getAttribute("min");
min.detach();
customPropsValue.append(getStringValue(min));
customPropsValue.append(" ");
customPropsValue.append(extractPeriodAndShift(element));
addCustomProperty(element, "old_definition_v0.9.4", customPropsValue.toString().trim());
}
}
private String extractPeriodAndShift(Element element) {
StringBuilder str = new StringBuilder();
List<Element> children = element.getChildren();
for (Element e : children) {
str.append(e.getName());
str.append("=");
str.append(e.getAttributeValue("value"));
str.append(e.getAttributeValue("unit"));
str.append(" ");
}
element.removeChild("period");
element.removeChild("shift");
return str.toString();
}
private String getStringValue(Attribute attr) {
return attr.getName() + "=" + attr.getValue();
}
private void update_ClocksMulitplierList(final Element rootElement) {
final String xpath = "./stimuliModel/clocks[@xsi:type=\"am:ClockMultiplierList\"]";
final List<Element> clocks = HelperUtil.getXpathResult(rootElement, xpath, Element.class,
AmaltheaNamespaceRegistry.getNamespace(ModelVersion._094, "am"),
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element element : clocks) {
element.setAttribute("type", "am:ClockStepList", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
update_ClockEntries(element);
}
}
private void update_ClockEntries(Element clockElement) {
List<Element> entries = clockElement.getChildren("entries");
for (Element entry : entries) {
Attribute multiplier = entry.getAttribute("multiplier");
multiplier.detach();
addCustomProperty(entry, "old_definition_v0.9.4", "multiplier=" + multiplier.getValue());
}
}
private void addCustomProperty(Element element, String key, String value) {
Element customProps = new Element("customProperties");
// set key
customProps.setAttribute("key", key);
// set value
Element valueElement = new Element("value");
valueElement.setAttribute("type", "am:StringObject", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
valueElement.setAttribute("value", value);
customProps.addContent(valueElement);
element.addContent(customProps);
}
private Element getSingleChild(final Element parent, String name) {
List<Element> list = parent.getChildren(name);
if (list.size() == 1) {
return list.get(0);
} else {
return null;
}
}
private String getNewClockType(final String oldClockType) {
switch (oldClockType) {
case "SinusFunction": case "TriangleFunction" : return "Function";
case "MultiplierList" : return "StepList";
}
return oldClockType;
}
}