blob: 91e54156593e51802fd00b7af843f3f177a65fe2 [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2015-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.converters081.impl;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
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.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;
/**
* This class is responsible for converting the Stimuli Model elements from 0.8.0 to 0.8.1 version format of AMALTHEA model
*
* @author mez2rng
*
*/
@Component(
property = {
ServiceConstants.INPUT_MODEL_VERSION_PROPERTY + "=0.8.0",
ServiceConstants.OUTPUT_MODEL_VERSION_PROPERTY + "=0.8.1"},
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> filename2documentMap, List<ICache> caches) {
LOGGER.info("Migration from 0.8.0 to 0.8.1 : Executing Stimuli converter for model file : {}",
targetFile.getName());
final Document root = filename2documentMap.get(targetFile);
if (root == null) {
return;
}
final Element rootElement = root.getRootElement();
updateAllModeValueListEntryElements(rootElement);
updateAllStimulusElements(rootElement);
updateCustomPropertiesForStimulus(rootElement);
}
private void updateCustomPropertiesForStimulus(Element rootElement) {
final StringBuilder xpathBuffer = new StringBuilder();
xpathBuffer.append(".//customProperties/value[@value]");
xpathBuffer.append("|");
xpathBuffer.append(".//customProperties/value/value");
xpathBuffer.append("|");
xpathBuffer.append(".//customProperties//values[@value]");
xpathBuffer.append("|");
xpathBuffer.append(".//customProperties//values/value");
Map<String, String> namesMap=new HashMap<>();
namesMap.put("ArrivalCurve","ArrivalCurveStimulus");
namesMap.put("InterProcess","InterProcessStimulus");
namesMap.put("Periodic","PeriodicStimulus");
namesMap.put("PeriodicEvent","VariableRateStimulus");
namesMap.put("Single","SingleStimulus");
namesMap.put("Sporadic","SporadicStimulus");
namesMap.put("Synthetic","SyntheticStimulus");
final List<Element> elements = HelperUtil.getXpathResult(
rootElement,
xpathBuffer.toString(),
Element.class,
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element element : elements) {
Attribute typeAttribute = element.getAttribute("type", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
Attribute valueAttribute = element.getAttribute("value");
Attribute hrefAttribute = element.getAttribute("href");
/*-
* Case 1: <value xsi:type="am:ReferenceObject" value="no-name?type=ArrivalCurve"/>
*
*/
if(typeAttribute !=null && valueAttribute !=null){
String value = valueAttribute.getValue();
final int indexOfEquals = value.indexOf('=');
if(indexOfEquals!=-1){
String stimulusName = value.substring(indexOfEquals+1, value.length());
if(namesMap.containsKey(stimulusName)){
String newValue = value.substring(0, indexOfEquals+1)+namesMap.get(stimulusName);
valueAttribute.setValue(newValue);
}
}
}
/*-
* Case 2: <value xsi:type="am:EventStimulus" href="amlt:/#foreignEventStimulus?type=EventStimulus"/>
*/
else if((valueAttribute == null) && (hrefAttribute !=null) && (typeAttribute !=null)){
updateStimulusTypeAttribute(element);
String value = hrefAttribute.getValue();
final int indexOfEquals = value.indexOf('=');
if(indexOfEquals!=-1){
String stimulusName = value.substring(indexOfEquals+1, value.length());
if(namesMap.containsKey(stimulusName)){
String newValue = value.substring(0, indexOfEquals+1)+namesMap.get(stimulusName);
hrefAttribute.setValue(newValue);
}
}
}
}
}
/**
* This method is used to migrate all EventStimulus elements + update type info of Stimulus elements (For further
* details, check : Bug 519925, Bug 519930 )
*
*
* @param rootElement
* Amalthea root element
*/
private void updateAllStimulusElements(Element rootElement) {
updateAllStimulusElementsDefinition(rootElement);
updateAllStimulusElementsReferences(rootElement);
}
private void updateAllStimulusElementsReferences(Element rootElement) {
Map<String, String> old_new_StimulusNamesMap=new HashMap<>();
old_new_StimulusNamesMap.put("ArrivalCurve", "ArrivalCurveStimulus");
old_new_StimulusNamesMap.put("InterProcess", "InterProcessStimulus");
old_new_StimulusNamesMap.put("Periodic", "PeriodicStimulus");
old_new_StimulusNamesMap.put("PeriodicEvent", "VariableRateStimulus");
old_new_StimulusNamesMap.put("Single", "SingleStimulus");
old_new_StimulusNamesMap.put("Sporadic", "SporadicStimulus");
old_new_StimulusNamesMap.put("Synthetic", "SyntheticStimulus");
final StringBuilder stimulusEventBuffer = new StringBuilder();
stimulusEventBuffer.append("./eventModel/events[@xsi:type=\"am:StimulusEvent\"]");
updateStimulusReferences(rootElement, old_new_StimulusNamesMap, stimulusEventBuffer, "entity",false);
final StringBuilder processBuffer = new StringBuilder();
processBuffer.append("./swModel/tasks");
processBuffer.append("|");
processBuffer.append("./swModel/isrs");
updateStimulusReferences(rootElement, old_new_StimulusNamesMap, processBuffer, "stimuli",false);
final StringBuilder interProcessActivationBuffer = new StringBuilder();
interProcessActivationBuffer.append("./swModel/tasks//calls[@xsi:type=\"am:InterProcessActivation\"]");
interProcessActivationBuffer.append("|");
interProcessActivationBuffer.append("./swModel/isrs//calls[@xsi:type=\"am:InterProcessActivation\"]");
updateStimulusReferences(rootElement, old_new_StimulusNamesMap, interProcessActivationBuffer, "stimulus",true);
}
private void updateStimulusReferences(Element rootElement, Map<String, String> old_new_StimulusNamesMap,
final StringBuilder stimulusEventBuffer, String variableName, boolean isInterProcessActivation) {
final List<Element> elements = HelperUtil.getXpathResult(
rootElement,
stimulusEventBuffer.toString(),
Element.class,
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element targetElement : elements) {
Attribute attribute = targetElement.getAttribute(variableName);
if (attribute != null) {
StringBuilder updatedValueBuffer = new StringBuilder();
StringTokenizer stk = new StringTokenizer(attribute.getValue());
while (stk.hasMoreTokens()) {
String nextToken = stk.nextToken();
updatedValueBuffer.append(getUpdatedStimulusReference(nextToken, old_new_StimulusNamesMap,isInterProcessActivation) + " ");
}
String trimmedValue = updatedValueBuffer.toString().trim();
if(trimmedValue.length()!=0){
attribute.setValue(trimmedValue);
}else{
attribute.detach();
}
}
List<Element> children = HelperUtil.getXpathResult(
targetElement,
"./"+variableName,
Element.class,
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element element : children) {
if(isInterProcessActivation){
//Note: in case of InterProcessActivation, only InterProcessStimulus is supported (for details refer : 519930)
String attributeValue = element.getAttributeValue("type", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
if(attributeValue!=null && ! attributeValue.equals("InterProcess") ){
element.detach();
continue;
}
}
/*-- element will also have the type information, if in the model, contents are defined using its super class */
updateStimulusTypeAttribute(element);
/*--- below code is used to update the references */
Attribute hrefAttribute = element.getAttribute("href");
if (hrefAttribute != null) {
String value = hrefAttribute.getValue();
String updatedValue = getUpdatedStimulusReference(value, old_new_StimulusNamesMap,isInterProcessActivation);
if (!value.equals(updatedValue)) {
hrefAttribute.setValue(updatedValue);
}
}
}
/*-
* update root elements type for InterProcessActivation as per the meta model change in 0.8.1:
*/
if(isInterProcessActivation){
Attribute typeAttribute = targetElement.getAttribute("type",AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
if (typeAttribute != null) {
String typeValue = typeAttribute.getValue();
if(typeValue.equals("am:InterProcessActivation")){
typeAttribute.setValue("am:InterProcessTrigger");
}
}
}
}
}
private String getUpdatedStimulusReference(String token, Map<String, String> old_new_StimulusNamesMap, boolean isInterProcessActivation) {
final int indexOfEquals = token.indexOf('=');
if(indexOfEquals!=-1){
String stimulusType = token.substring(indexOfEquals+1, token.length());
//Note: in case of InterProcessActivation, only InterProcessStimulus is supported (for details refer : 519930)
if(isInterProcessActivation && ! stimulusType.equals("InterProcess")){
return "";
}
if(old_new_StimulusNamesMap.containsKey(stimulusType)) {
return token.substring(0, indexOfEquals+1)+old_new_StimulusNamesMap.get(stimulusType);
}
}
return token;
}
private void updateAllStimulusElementsDefinition(Element rootElement) {
final StringBuilder xpathBuffer = new StringBuilder();
xpathBuffer.append("./stimuliModel/stimuli");
final List<Element> stimulusElements = HelperUtil.getXpathResult(
rootElement,
xpathBuffer.toString(),
Element.class,
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element stimulusElement : stimulusElements) {
updateStimulusTypeAttribute(stimulusElement);
}
}
/**
* This method is used to update the type attribute of both Stimulus definition and references
* @param stimulusElement
*/
private void updateStimulusTypeAttribute(Element stimulusElement) {
Attribute typeAttribute = stimulusElement.getAttribute("type", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
if (typeAttribute != null) {
String stimulusType = typeAttribute.getValue();
if (stimulusType.equals("am:EventStimulus")) {
/*-Model migration of EventStimulus element as per Bug 519925*/
updateEventStimulus(stimulusElement);
} else if (stimulusType.equals("am:ArrivalCurve")) {
typeAttribute.setValue("am:ArrivalCurveStimulus");
} else if (stimulusType.equals("am:InterProcess")) {
typeAttribute.setValue("am:InterProcessStimulus");
} else if (stimulusType.equals("am:Periodic")) {
typeAttribute.setValue("am:PeriodicStimulus");
} else if (stimulusType.equals("am:PeriodicEvent")) {
typeAttribute.setValue("am:VariableRateStimulus");
} else if (stimulusType.equals("am:Single")) {
typeAttribute.setValue("am:SingleStimulus");
} else if (stimulusType.equals("am:Sporadic")) {
typeAttribute.setValue("am:SporadicStimulus");
} else if (stimulusType.equals("am:Synthetic")) {
typeAttribute.setValue("am:SyntheticStimulus");
}
}
}
/**
* This method is used to migrate all EventStimulus elements + (For further
* details, check : Bug 519925 )
* @param stimulusElement
*/
private void updateEventStimulus(Element stimulusElement) {
Attribute triggerAttribute = stimulusElement.getAttribute("trigger");
if(triggerAttribute!=null){
triggerAttribute.setName("triggeringEvents");
}
List<Element> triggerElements = stimulusElement.getChildren("trigger");
if(triggerElements !=null ){
for (Element triggerElement : triggerElements) {
triggerElement.setName("triggeringEvents");
}
}
}
/**
* This method is used to migrate all ModeValueListEntry elements (For further
* details, check : Bug 519860 )
*
*
* @param rootElement
* Amalthea root element
*/
private void updateAllModeValueListEntryElements(Element rootElement) {
final StringBuilder xpathBuffer = new StringBuilder();
xpathBuffer.append("./stimuliModel/stimuli/setModeValueList/entries");
xpathBuffer.append("|");
xpathBuffer.append("./stimuliModel/stimuli/enablingModeValueList/entries");
xpathBuffer.append("|");
xpathBuffer.append("./stimuliModel/stimuli/disablingModeValueList/entries");
final List<Element> modeValueListEntryElements = HelperUtil.getXpathResult(
rootElement,
xpathBuffer.toString(),
Element.class,
AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
for (Element modeValueListEntry : modeValueListEntryElements) {
modeValueListEntry.setAttribute("type", "am:ModeValue", AmaltheaNamespaceRegistry.getGenericNamespace("xsi"));
}
}
}