/** | |
******************************************************************************** | |
* Copyright (c) 2015-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.converters072.impl; | |
import java.io.File; | |
import java.util.Iterator; | |
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.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.7.1", | |
ServiceConstants.OUTPUT_MODEL_VERSION_PROPERTY + "=0.7.2"}, | |
service = IConverter.class) | |
public class SwConverter extends AbstractConverter { | |
@Reference | |
SessionLogger logger; | |
@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.7.1 to 0.7.2 : Executing SW converter for model file : {0}", targetFile.getName()); | |
final Document root = filename2documentMap.get(targetFile); | |
if (root == null) { | |
return; | |
} | |
final Element rootElement = root.getRootElement(); | |
updateBuffering(rootElement); | |
updateSamplingType(rootElement); | |
updateInstructionsConstant(rootElement); | |
updateInstructionsDeviation(rootElement); | |
updateProbabilityGroup(rootElement); | |
updateGroup(rootElement); | |
updatePreemption(rootElement); | |
} | |
/** | |
* This method is used to migrate the "buffered" attribute of Label and LabelAccess | |
* | |
* For migration of buffered attribute inside Label, below are the steps which are followed: | |
* | |
* <pre> | |
* | |
* *. LabelBufferring is replaced with DataStability element | |
* - If LabelBuffering value is "buffered" then the corresponding value of "dataStability" is set as "CustomProtection" | |
* - If LabelBuffering value is "notBuffered" then the corresponding value of "dataStability" is set as "noProtection" | |
* - If LabelBuffering value is "_undefined_" (default) then the corresponding value of "dataStability" is set as "_undefined_" (default) | |
* | |
* </pre> | |
* | |
* *For migration of buffered attribute inside LabelAccess, below are the steps which are followed: | |
* | |
* <pre> | |
* | |
* *. LabelAccessBufferring is replaced with DataStability element | |
* - If LabelAccessBufferring value is "inherited" then the corresponding value of "dataStability" is set as "inherited" | |
* - If LabelAccessBufferring value is "buffered" then the corresponding value of "dataStability" is set as "customProtection" | |
* - If LabelAccessBufferring value is "notBuffered" then the corresponding value of "dataStability" is set as "noProtection" | |
* - If LabelAccessBufferring value is "_undefined_" (default) then the corresponding value of "dataStability" is set as "_undefined_" (default) | |
* | |
* </pre> | |
* | |
* @param rootElement | |
*/ | |
private void updateBuffering(final Element rootElement) { | |
final StringBuilder labelXpathBuffer = new StringBuilder(); | |
labelXpathBuffer.append("./swModel/labels"); | |
final List<Element> elements = HelperUtil.getXpathResult( | |
rootElement, | |
labelXpathBuffer.toString(), | |
Element.class, | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
for (final Element labelElement : elements) { | |
final Attribute bufferedAttribute = labelElement.getAttribute("buffered"); | |
if (bufferedAttribute != null) { | |
bufferedAttribute.setName("dataStability"); | |
final String bufferedValue = bufferedAttribute.getValue(); | |
if (bufferedValue.equals("buffered")) { | |
bufferedAttribute.setValue("customProtection"); | |
} | |
else if (bufferedValue.equals("notBuffered")) { | |
bufferedAttribute.setValue("noProtection"); | |
} | |
} | |
} | |
final StringBuilder labelAccessXpathBuffer = new StringBuilder(); | |
labelAccessXpathBuffer.append("./swModel/runnables//runnableItems[@xsi:type=\"am:LabelAccess\"]"); | |
labelAccessXpathBuffer.append("|"); | |
labelAccessXpathBuffer.append("./swModel/runnables//runnableItem[@xsi:type=\"am:LabelAccess\"]"); | |
final List<Element> labelAccesselements = HelperUtil.getXpathResult(rootElement, | |
labelAccessXpathBuffer.toString(), Element.class, AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
for (final Element labelAccessElement : labelAccesselements) { | |
final Attribute bufferedAttribute = labelAccessElement.getAttribute("buffered"); | |
if (bufferedAttribute != null) { | |
bufferedAttribute.setName("dataStability"); | |
final String bufferedValue = bufferedAttribute.getValue(); | |
if (bufferedValue.equals("inherited")) { | |
bufferedAttribute.setValue("inherited"); | |
} | |
else if (bufferedValue.equals("buffered")) { | |
bufferedAttribute.setValue("customProtection"); | |
} | |
else if (bufferedValue.equals("notBuffered")) { | |
bufferedAttribute.setValue("noProtection"); | |
} | |
} | |
} | |
} | |
/** | |
* | |
* SamplingType Enum is part of Deviation object till 0.7.1 | |
* | |
* Based on bugzilla : 508523, SamplingType is shifted from Deviation element to Boundaries element (sub-class of | |
* Distribution) | |
* | |
* -- As a part of migration, SamplingType content part of Deviation is associted to Boundaries. In case | |
* Distribution of type Distribution is not present inside Deviation, SamplingType content is not associated and | |
* lost (as expected) | |
* | |
* Note: Deviation element is used inside Stimulus model, HW model, OS model, SW model | |
* | |
* @param rootElement | |
*/ | |
private void updateSamplingType(final Element rootElement) { | |
final StringBuilder xpathBuffer = new StringBuilder(); | |
xpathBuffer.append("./stimuliModel/stimuli/stimulusDeviation"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./hwModel/accessPaths/latencies[@xsi:type=\"am:LatencyDeviation\"]/deviation"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./osModel/operatingSystems/taskSchedulers/schedulingUnit/instructions/deviation"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./osModel/operatingSystems/interruptControllers/schedulingUnit/instructions/deviation"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./osModel/osOverheads//deviation"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./swModel/runnables//deviation"); | |
final List<Element> elements = HelperUtil.getXpathResult(rootElement, xpathBuffer.toString(), Element.class, | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
for (final Element deviation : elements) { | |
/*- updating the type of the Element as per change introduced in 0.7.2*/ | |
final Attribute samplingTypeAttribute = deviation.getAttribute("samplingType"); | |
if (samplingTypeAttribute != null) { | |
final String value = samplingTypeAttribute.getValue(); | |
final Element distribution = deviation.getChild("distribution"); | |
if (distribution != null) { | |
final String distributionType = distribution.getAttributeValue("type", | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
/*- Setting "samplingType" to "distribution" --> only if the distribution element is of type "am:Boundaries" */ | |
if (distributionType != null && distributionType.equals("am:Boundaries")) { | |
distribution.setAttribute("samplingType", value); | |
} | |
} | |
deviation.removeAttribute(samplingTypeAttribute); | |
} | |
} | |
} | |
private void updateInstructionsConstant(final Element rootElement) { | |
final StringBuilder xpathBuffer = new StringBuilder(); | |
xpathBuffer.append("./swModel/runnables//runnableItems[@xsi:type=\"am:InstructionsConstant\"]"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./swModel/runnables//runnableItem[@xsi:type=\"am:InstructionsConstant\"]"); | |
final List<Element> elements = HelperUtil.getXpathResult(rootElement, xpathBuffer.toString(), Element.class, | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
for (final Element instructionsConstantElement : elements) { | |
/*- updating the type of the Element as per change introduced in 0.7.2*/ | |
final Attribute typeAttribute = instructionsConstantElement.getAttribute("type", | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
typeAttribute.setValue("am:RunnableInstructions"); | |
final Attribute valueAttribute = instructionsConstantElement.getAttribute("value"); | |
final Element subInstructionsConstantElement = new Element("default"); | |
subInstructionsConstantElement.setAttribute("type", "am:InstructionsConstant", | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
if (valueAttribute != null) { | |
subInstructionsConstantElement.setAttribute("value", valueAttribute.getValue()); | |
instructionsConstantElement.removeAttribute(valueAttribute); | |
} | |
instructionsConstantElement.addContent(subInstructionsConstantElement); | |
} | |
} | |
private void updateInstructionsDeviation(final Element rootElement) { | |
final StringBuilder xpathBuffer = new StringBuilder(); | |
xpathBuffer.append("./swModel/runnables//runnableItems[@xsi:type=\"am:InstructionsDeviation\"]"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./swModel/runnables//runnableItem[@xsi:type=\"am:InstructionsDeviation\"]"); | |
final List<Element> elements = HelperUtil.getXpathResult(rootElement, xpathBuffer.toString(), Element.class, | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
for (final Element instructionsDeviationElement : elements) { | |
/*- updating the type of the Element as per change introduced in 0.7.2*/ | |
final Attribute typeAttribute = instructionsDeviationElement.getAttribute("type", | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
typeAttribute.setValue("am:RunnableInstructions"); | |
final Element subInstructionsDeviationElement = new Element("default"); | |
subInstructionsDeviationElement.setAttribute("type", "am:InstructionsDeviation", | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
final List<Element> instructionsDeviationChildElements = instructionsDeviationElement.getChildren(); | |
final Iterator<Element> instructionsDeviationChildElements_iterator = instructionsDeviationChildElements | |
.iterator(); | |
while (instructionsDeviationChildElements_iterator.hasNext()) { | |
final Element nextChildElement = instructionsDeviationChildElements_iterator.next(); | |
instructionsDeviationChildElements_iterator.remove(); | |
subInstructionsDeviationElement.addContent(nextChildElement); | |
} | |
instructionsDeviationElement.addContent(subInstructionsDeviationElement); | |
} | |
} | |
private void updatePreemption(final Element rootElement) { | |
final StringBuilder xpathBuffer = new StringBuilder(); | |
xpathBuffer.append("./swModel/processPrototypes[@preemption=\"unknown\"]"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./swModel/tasks[@preemption=\"unknown\"]"); | |
final List<Element> elements = HelperUtil.getXpathResult(rootElement, xpathBuffer.toString(), Element.class, | |
AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
for (final Element element : elements) { | |
element.removeAttribute("preemption"); | |
} | |
} | |
/** | |
* Due to removal of element : DeviationRunnableItem | |
* | |
* | |
* @param rootElement | |
*/ | |
private void updateGroup(final Element rootElement) { | |
/*- | |
* Input : | |
* | |
* <runnableItems xsi:type="am:Group" ordered="false"> | |
* <items> | |
* <runnableItem xsi:type="am:RunnableProbabilitySwitch"> | |
* <entries probability="0" /> | |
* </runnableItem> | |
* </items> | |
* </runnableItems> | |
* | |
*/ | |
final StringBuilder xpathBuffer = new StringBuilder(); | |
xpathBuffer.append("./swModel/runnables//runnableItems[@xsi:type=\"am:Group\"]"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./swModel/runnables//runnableItem[@xsi:type=\"am:Group\"]"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append( | |
"./swModel/runnables//items[@xsi:type=\"am:Group\"]"); /*- note: the last Xpath is introduced, as the model is adapted to 0.7.2 in update_ProbabilityGroup method*/ | |
final List<Element> runnableItemElements = HelperUtil.getXpathResult(rootElement, xpathBuffer.toString(), | |
Element.class, AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
for (final Element runnableItemElement : runnableItemElements) { | |
final List<Element> deviationRunnableItemsList = HelperUtil.getXpathResult(runnableItemElement, "./items", | |
Element.class); | |
final Iterator<Element> deviationRunnableItemsListIterator = deviationRunnableItemsList.iterator(); | |
while (deviationRunnableItemsListIterator.hasNext()) { | |
final Element deviationRunnableItemElement = deviationRunnableItemsListIterator.next(); | |
final List<Element> childRunnableItems = HelperUtil.getXpathResult(deviationRunnableItemElement, | |
"./runnableItem", Element.class); | |
if (childRunnableItems != null && !childRunnableItems.isEmpty()) { | |
final Element childRunnableItem = childRunnableItems.get(0); | |
/*- disassociating the runnableItem from its parent DeviationRunnableItem */ | |
deviationRunnableItemElement.removeContent(childRunnableItem); | |
childRunnableItem.setName("items"); | |
runnableItemElement.removeContent(deviationRunnableItemElement); | |
/*- now associate RunnableItem to the Group directly */ | |
runnableItemElement.addContent(childRunnableItem); | |
} else { | |
/*- this is the case where empty items tag is present (i.e. DeviationRunnableItem -> without RunnableItems */ | |
runnableItemElement.removeContent(deviationRunnableItemElement); | |
} | |
/*- DeviationRunnableItem is removed from metamodel -> RunnableItem which is present inside DeviationRunnableItem is directly associated inside Group | |
* Due to the above reason : DeviationRunnableElement is removed from Group | |
* */ | |
} | |
} | |
} | |
/** | |
* Migration of ProbabilityGroup: | |
* | |
* Based on changes introduced in 0.7.2, ProbabilityGroup is removed and its equivalent is | |
* "RunnableProbabilityGroup" (associated to Runnable elements) | |
* | |
* From 0.7.1 - ProbabilityGroup structure is as shown below: | |
* | |
* <pre> | |
* ProbabilityGroup | |
* - ProbabilityRunnableItem items[0-*] | |
* - EInt probability[0-1] | |
* - RunnableItem runnableItem[0-1] | |
* </pre> | |
* | |
* From 0.7.2 - RunnableProbabilitySwitch structure is as shown below | |
* | |
* <pre> | |
* RunnableProbabilitySwitch | |
* - ProbabilitySwitchEntry entries[0-*] | |
* - EDouble probability[0-1] | |
* - RunnableItem items[0-*] | |
* </pre> | |
* | |
* * | |
* | |
* @param rootElement | |
*/ | |
private void updateProbabilityGroup(final Element rootElement) { | |
final StringBuilder xpathBuffer = new StringBuilder(); | |
xpathBuffer.append("./swModel/runnables//runnableItems[@xsi:type=\"am:ProbabilityGroup\"]"); | |
xpathBuffer.append("|"); | |
xpathBuffer.append("./swModel/runnables//runnableItem[@xsi:type=\"am:ProbabilityGroup\"]"); | |
final List<Element> runnableItemElements = HelperUtil.getXpathResult(rootElement, xpathBuffer.toString(), | |
Element.class, AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
for (final Element runnableItemElement : runnableItemElements) { | |
final Attribute typeAttribute = runnableItemElement.getAttribute("type", AmaltheaNamespaceRegistry.getGenericNamespace("xsi")); | |
typeAttribute.setValue( | |
"am:RunnableProbabilitySwitch"); /*-changing the type from ProbabilityGroup to RunnableProbabilitySwitch*/ | |
final List<Element> itemsElements = runnableItemElement.getChildren("items"); | |
for (final Element itemsElement : itemsElements) { | |
itemsElement.setName("entries"); /*-changing the identifier name from items to entries*/ | |
final Element childRunnableItemElement = itemsElement.getChild("runnableItem"); | |
if (childRunnableItemElement != null) { | |
childRunnableItemElement | |
.setName("items"); /*-changing the identifier name from runnableItem to items*/ | |
} | |
} | |
} | |
} | |
} |