| /********************************************************************************* |
| * Copyright (c) 2022 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.converters300.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.util.sessionlog.SessionLogger; |
| import org.jdom2.Attribute; |
| import org.jdom2.Document; |
| import org.jdom2.Element; |
| import org.jdom2.Namespace; |
| 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 + "=2.2.0", |
| ServiceConstants.OUTPUT_MODEL_VERSION_PROPERTY + "=3.0.0" |
| }, |
| service = IConverter.class) |
| |
| public class DatatypeConverter extends AbstractConverter { |
| |
| private static final String ID = "id"; |
| private static final String NAME = "name"; |
| private static final String HREF = "href"; |
| private static final String TYPE = "type"; |
| private static final String TYPE_DEF = "typeDef"; |
| private static final String TYPE_DATA_TYPE_DEFINITION = "?type=DataTypeDefinition"; |
| private static final String DATA_TYPE = "dataType"; |
| |
| @Reference |
| SessionLogger logger; |
| |
| @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} to {1} : Executing Datatype converter for model file : {2}", |
| getInputModelVersion(), getOutputModelVersion(), targetFile.getName()); |
| |
| basicConvert(targetFile, fileDocumentMapping); |
| } |
| |
| private void basicConvert(File file, Map<File, Document> map) { |
| // get document root |
| final Document document = map.get(file); |
| if (document == null) { |
| return; |
| } |
| |
| final Element rootElement = document.getRootElement(); |
| |
| updateSoftwareDatatypes(rootElement); |
| updateComponentDatatypes(rootElement); |
| } |
| |
| private void updateSoftwareDatatypes(Element rootElement) { |
| final Namespace am = AmaltheaNamespaceRegistry.getNamespace(getInputModelVersion(), "am"); |
| final Namespace xsi = AmaltheaNamespaceRegistry.getGenericNamespace("xsi"); |
| final Namespace xmi = AmaltheaNamespaceRegistry.getGenericNamespace("xmi"); |
| |
| // get types of Labels and Channels |
| |
| final StringBuilder xpathBuilder = new StringBuilder(); |
| xpathBuilder.append("./swModel/labels/dataType"); |
| xpathBuilder.append("|"); |
| xpathBuilder.append("./swModel/channels/elementType"); |
| final List<Element> entries = HelperUtil.getXpathResult(rootElement, xpathBuilder.toString(), Element.class, am, xsi); |
| |
| if (entries == null) { |
| return; |
| } |
| |
| // Change types |
| |
| for (Element entry : entries) { |
| Element parent = entry.getParentElement(); // Channel or Label |
| |
| Attribute typeAttr = entry.getAttribute(TYPE, xsi); |
| if ("am:TypeRef".equals(typeAttr.getValue())) { |
| |
| // *** top level element is a type reference *** |
| |
| Attribute attribute = entry.getAttribute(TYPE_DEF); |
| Element child = entry.getChild(TYPE_DEF); |
| |
| if (attribute != null ) { |
| // handle local reference |
| parent.setAttribute(entry.getName(), entry.getAttributeValue(TYPE_DEF)); |
| entry.detach(); |
| } |
| |
| if (child != null ) { |
| // handle cross file reference |
| typeAttr.setValue(child.getAttributeValue(TYPE, xsi)); |
| if (child.getAttribute(HREF) != null) { |
| entry.setAttribute(child.getAttribute(HREF).clone()); |
| } |
| child.detach(); |
| } |
| |
| if (attribute == null && child == null) { |
| // no valid reference |
| entry.detach(); |
| } |
| |
| } else { |
| |
| // *** inline type definition *** |
| |
| String parentId = parent.getAttributeValue(ID, xmi); |
| String parentIdWithoutType = parentId.substring(0, parentId.lastIndexOf("?type=")); |
| String parentName = parent.getAttributeValue(NAME); |
| |
| String parentType = parent.getName().replace("s", ""); // "label" or "channel" |
| String postfix = " (migrated " + parentType + " type)"; |
| |
| String genId = parentIdWithoutType + HelperUtil.encodeName(postfix) + TYPE_DATA_TYPE_DEFINITION; |
| String genName = parentName + postfix; |
| |
| // refer to new datatype (local reference) |
| parent.setAttribute(entry.getName(), genId); |
| |
| // create new datatype (in same file) |
| Element newTypeDefinition = new Element("typeDefinitions"); |
| newTypeDefinition.setAttribute(TYPE, "am:DataTypeDefinition", xsi); |
| newTypeDefinition.setAttribute(ID, genId, xmi); |
| newTypeDefinition.setAttribute(NAME, genName); |
| |
| // set namespace according to parent element |
| HelperUtil.copyElementAttributeOrElement(parent, newTypeDefinition, "namespace"); |
| |
| // move local type definition to new datatype |
| entry.detach(); |
| entry.setName(DATA_TYPE); |
| newTypeDefinition.addContent(entry); |
| |
| // add new type to content tree |
| rootElement.getChild("swModel").addContent(newTypeDefinition); |
| } |
| } |
| } |
| |
| private void updateComponentDatatypes(Element rootElement) { |
| final Namespace am = AmaltheaNamespaceRegistry.getNamespace(getInputModelVersion(), "am"); |
| final Namespace xsi = AmaltheaNamespaceRegistry.getGenericNamespace("xsi"); |
| |
| // get types of Labels and Channels |
| |
| final StringBuilder xpathBuilder = new StringBuilder(); |
| xpathBuilder.append("./componentsModel/interfaces"); |
| xpathBuilder.append("|"); |
| xpathBuilder.append("./componentsModel/interfaces//subInterfaces"); |
| final List<Element> entries = HelperUtil.getXpathResult(rootElement, xpathBuilder.toString(), Element.class, am, xsi); |
| |
| if (entries == null) { |
| return; |
| } |
| |
| // Change element name from "datatype" to "dataType" |
| |
| for (Element entry : entries) { |
| Attribute attribute = entry.getAttribute("datatype"); |
| if (attribute != null) { |
| attribute.setName(DATA_TYPE); |
| } |
| |
| Element child = entry.getChild("datatype"); |
| if (child != null) { |
| child.setName(DATA_TYPE); |
| } |
| } |
| } |
| |
| } |