blob: af32e0e082c81ec2cd0609f697a77f4dfb0a442b [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2015-2019 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.converters.common.utils;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.app4mc.amalthea.converters.common.base.ICache;
import org.eclipse.app4mc.amalthea.converters.common.xpath.utils.BulkXpathOperation;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractAttributeRefCacheBuilder implements ICache {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAttributeRefCacheBuilder.class);
Map<File, Map<String, Object>> map = new HashMap<>();
@Override
public Map<File, Map<String, Object>> getCacheMap() {
return this.map;
}
@Override
public void clearCacheMap() {
this.map.clear();
}
/**
* This method is used to grab all Elements referred by legacy URI fragments and build a Map containing key as
* URIFragment and value as corresponding Element
*
* Expected keys:
*
* URIFRAGMENT_SCHEDULER_REFS_ATRIBUTES
*
* @param targetFile
* @param rootDocument
* @return
*/
@SuppressWarnings("unchecked")
protected Map<String, Element> getAllElements_referred_by_URIFragments(final File targetFile,
final Document rootDocument, final String URIFRAGMENT_ELEMENT_REFS_ATTRIBUTES) {
final Map<String, List<Attribute>> uriFragment2schedulerRefAttribsMap =
(Map<String, List<Attribute>>) getCacheMap().get(targetFile).get(URIFRAGMENT_ELEMENT_REFS_ATTRIBUTES);
if (uriFragment2schedulerRefAttribsMap == null) {
LOGGER.error("cache : \"{}\" not populated", URIFRAGMENT_ELEMENT_REFS_ATTRIBUTES);
return new HashMap<>();
}
final Set<String> uriFragments = uriFragment2schedulerRefAttribsMap.keySet();
final Map<String, Element> uriFragment2ElementsMap = getAllElements_referred_by_URIFragments(rootDocument,
uriFragments);
return uriFragment2ElementsMap;
}
// TODO:Use Xpath bulk operation
protected Map<String, Element> getAllElements_referred_by_URIFragments(final Document rootDocument,
final Set<String> uriFragments) {
final Map<String, Element> uriFragment2ElementsMap = new HashMap<>();
/*- temporary Map to store key as URIFragment and Vale as Xpath*/
final Map<String, String> uriFragment2XpathStringMap = new HashMap<>();
/*- Map to store the result of */
Map<String, List<Element>> xpath2ElementsMap = new HashMap<>();
for (final String uriFragment : uriFragments) {
uriFragment2XpathStringMap.put(uriFragment, getXpathString(uriFragment));
}
/*- Bulk operation applied to fetch the JDOM Element's to improve the performance */
final BulkXpathOperation bulkXpathOperation = new BulkXpathOperation();
xpath2ElementsMap = bulkXpathOperation.invokeXpath(rootDocument, uriFragment2XpathStringMap.values());
for (final String uriFragment : uriFragments) {
if (!uriFragment2ElementsMap.containsKey(uriFragment)) {
final String xpath = uriFragment2XpathStringMap.get(uriFragment);
final List<Element> list = xpath2ElementsMap.get(xpath);
if (!list.isEmpty()) {
uriFragment2ElementsMap.put(uriFragment, list.get(0));
} else {
LOGGER.error("No references can be found for : {} corresponding Xpath used is : {}", uriFragment, xpath);
}
}
}
return uriFragment2ElementsMap;
}
@SuppressWarnings("unchecked")
protected void addAttributeTo_Href_URIFragment_Attributes_Cache(
File targetFile,
File refFile,
String uriFragment_with_fileInfo,
String fileNameInfo,
String localURIFragment,
Attribute attribute,
String HREF_URIFRAGMENT_ELEMENT_REFS_ATRIBUTES) {
Map<File, Map<String, Map<String, List<Attribute>>>> reffile2uriFragment2schedulerRefAttribsMap =
((Map<File, Map<String, Map<String, List<Attribute>>>>) getCacheMap().get(targetFile).get(HREF_URIFRAGMENT_ELEMENT_REFS_ATRIBUTES));
Map<String, Map<String, List<Attribute>>> table = reffile2uriFragment2schedulerRefAttribsMap.get(refFile);
if (table == null) {
table = new HashMap<>();
reffile2uriFragment2schedulerRefAttribsMap.put(refFile, table);
}
Map<String, List<Attribute>> attributeMap = table.get(uriFragment_with_fileInfo);
List<Attribute> attributes = null;
if (attributeMap == null) {
attributeMap = new HashMap<>();
table.put(uriFragment_with_fileInfo, attributeMap);
} else {
attributes = attributeMap.get(localURIFragment);
}
if (attributes == null) {
attributes = new ArrayList<>();
attributeMap.put(localURIFragment, attributes);
}
attributes.add(attribute);
}
/**
* <pre>
* This method is used to get Xpath String from URIFragment
*
* Example: <br>
*
* Case 1:
* If input for this method is : //@osModel/@scheduler.0 <br>
* This method will return : //osModel/scheduler[0]
*
* Case 2:
*
* If input for this method is : //@osModel/@operatingSystems.0/@taskSchedulers.0
* This method will return : //osModel/operatingSystems[0]/taskSchedulers[0]
* </pre>
*
* @param uriFragment
* @return
*/
protected String getXpathString_old(String uriFragment) {
uriFragment = uriFragment.replace("@", "");
if (uriFragment.contains(".")) {
final int lastIndexOf = uriFragment.lastIndexOf('.');
final String substring = uriFragment.substring(lastIndexOf + 1);
try {
/*- In EMF first element of array starts with index 0. And the same is used for URI fragment*/
/*- In Xpath 1st element of array starts with index 1 */
/*- Note: For conversion of URIFragment to Xpath, array index should be incremented by 1 */
final int arrayIndex = Integer.parseInt(substring) + 1;
uriFragment = uriFragment.substring(0, lastIndexOf) + "[" + arrayIndex + "]";
}
catch (final Exception e) {
LOGGER.error(
"Exception occured during conversion of URIFragment : {} to Xpath String", uriFragment, e);
throw e;
}
}
return uriFragment;
}
/**
* <pre>
* This method is used to get Xpath String from URIFragment
*
* Example: <br>
*
* Case 1:
* If input for this method is : //@osModel/@scheduler.0 <br>
* This method will return : //osModel/scheduler[0]
*
* Case 2:
*
* If input for this method is : //@osModel/@operatingSystems.0/@taskSchedulers.0
* This method will return : //osModel/operatingSystems[0]/taskSchedulers[0]
* </pre>
*
* @param uriFragment
* @return
*/
protected String getXpathString(String uriFragment) {
uriFragment = uriFragment.replace("@", "");
if (uriFragment.contains(".")) {
char[] charArray = uriFragment.toCharArray();
boolean isBuildingIndex = false;
StringBuilder xpathBuffer = new StringBuilder();
StringBuilder indexBuffer = new StringBuilder();
for (int i = 0; i < charArray.length; i++) {
if (charArray[i] == '.') {
xpathBuffer.append("[");
isBuildingIndex = true;
indexBuffer = new StringBuilder();
} else if (isBuildingIndex && (charArray[i] == '/')) {
addIndexToBuffer(xpathBuffer, indexBuffer);
indexBuffer = new StringBuilder();
xpathBuffer.append("]");
xpathBuffer.append("/");
isBuildingIndex = false;
} else if (isBuildingIndex) {
indexBuffer.append(charArray[i]);
} else {
xpathBuffer.append(charArray[i]);
}
}
if (isBuildingIndex) {
addIndexToBuffer(xpathBuffer, indexBuffer);
xpathBuffer.append("]");
}
uriFragment = xpathBuffer.toString();
}
return uriFragment;
}
private void addIndexToBuffer(StringBuilder xpathBuffer, StringBuilder indexBuffer) {
try {
long parseLong = Long.parseLong(indexBuffer.toString());
/*
* As Xpath index starts with 1 and EMF index starts with 0
* ===> during the conversion of uri fragment to Xpath ==> index is incremented by 1
*/
xpathBuffer.append(parseLong + 1);
} catch (Exception e) {
xpathBuffer.append(indexBuffer);
}
}
/**
* This method is used to grab all the Attributes referring to legacy format of URI fragments and group them
* accordingly based on key as URIFragment
*
* @param rootDocument
* @return
*/
protected Map<String, List<Attribute>> getAllAttributes_containing_URIFragments(final Document rootDocument,
final String xPath_for_attributes, final Namespace... nameSpaces) {
final List<Attribute> schedulerAttributes = HelperUtil.getXpathResult(rootDocument, xPath_for_attributes,
Attribute.class, nameSpaces);
/*- map containing key as URIFragment and value as List of Attribute objects */
final Map<String, List<Attribute>> uriFragment2AttributesMap = new HashMap<>();
for (final Attribute attribute : schedulerAttributes) {
final String uriFragment = attribute.getValue();
if (!uriFragment2AttributesMap.containsKey(uriFragment)) {
uriFragment2AttributesMap.put(uriFragment, new ArrayList<>());
}
uriFragment2AttributesMap.get(uriFragment).add(attribute);
}
return uriFragment2AttributesMap;
}
/**
* <pre>
* xpath_elementtype_href_attribute :
* ".//scheduler/@href[contains(., \"/\")]"
*
* </pre>
*
* @param targetFile
* @param rootDocument
* @param xpath_elementtype_href_attribute
*/
protected void populateAllHREF_ElementAttributes_having_legacy_URI_refs(final File targetFile,
final Document rootDocument, final String xpath_elementtype_href_attribute,
final String HREF_URIFRAGMENT_ELEMENT_REFS_ATRIBUTES, final Namespace... namespaces) {
final List<Attribute> schedulerHrefs = HelperUtil.getXpathResult(rootDocument,
xpath_elementtype_href_attribute, Attribute.class, namespaces);
final HashMap<String, File> refFileInfoMap = new HashMap<>();
final Map<File, Map<String, Map<String, List<Attribute>>>> reffile2uriFragment2schedulerRefAttribsMap = new HashMap<>();
/*- Adding elements into Cache */
getCacheMap().get(targetFile).put(HREF_URIFRAGMENT_ELEMENT_REFS_ATRIBUTES,
reffile2uriFragment2schedulerRefAttribsMap);
loop: for (final Attribute attribute : schedulerHrefs) {
final String uriFragment_with_fileInfo = attribute.getValue();
final int indexOfHash = uriFragment_with_fileInfo.indexOf('#');
if (indexOfHash != -1) {
final String fileNameInfo = uriFragment_with_fileInfo.substring(0, indexOfHash);
final String localURIFragment = uriFragment_with_fileInfo.substring(indexOfHash + 1);
// verify if the localURIFragment is of old format and not XMI ID
if (! localURIFragment.contains("//")) {
// this is the case of UUID (XMI ID) being present as a reference. It is not required to store such
// elements in the cache
continue loop;
}
final File refFile = getRefFile(targetFile, refFileInfoMap, fileNameInfo);
if (refFile != null) {
addAttributeTo_Href_URIFragment_Attributes_Cache(targetFile, refFile, uriFragment_with_fileInfo,
fileNameInfo, localURIFragment, attribute, HREF_URIFRAGMENT_ELEMENT_REFS_ATRIBUTES);
}
else {
LOGGER.error("Skipping attribut with value : {}", uriFragment_with_fileInfo);
}
}
}
}
protected File getRefFile(File targetFile, HashMap<String, File> refFileInfoMap, String fileNameInfo) {
File referredFile = null;
if (!refFileInfoMap.containsKey(fileNameInfo)) {
referredFile = new File(fileNameInfo);
if (!referredFile.exists()) {
referredFile = new File(targetFile.getParent(), fileNameInfo);
if (!referredFile.exists()) {
referredFile = null;
LOGGER.error("Unable to find the referred file : {}", fileNameInfo);
}
}
refFileInfoMap.put(fileNameInfo, referredFile);
} else {
referredFile = refFileInfoMap.get(fileNameInfo);
}
return referredFile;
}
@SuppressWarnings("unchecked")
protected void populate_All_UUID_Elements(File targetFile, Document rootDocument, String xpath, String uuidElement, Namespace... nameSpaces) {
Map<String, Element> uuid2elementMap = null;
if (!getCacheMap().get(targetFile).containsKey(uuidElement)) {
uuid2elementMap = new HashMap<>();
getCacheMap().get(targetFile).put(uuidElement, uuid2elementMap);
}
else {
uuid2elementMap = (Map<String, Element>) getCacheMap().get(targetFile).get(uuidElement);
}
final List<Element> elements = HelperUtil.getXpathResult(rootDocument, xpath, Element.class, nameSpaces);
for (final Element element : elements) {
final Attribute attribute = element.getAttribute("id", AmaltheaNamespaceRegistry.getGenericNamespace("xmi"));
if (attribute != null) {
uuid2elementMap.put(attribute.getValue(), element);
}
}
}
@SuppressWarnings("unchecked")
protected void populate_All_Elements_With_Name(File targetFile, Document rootDocument, String xpath, String elementName, Namespace... nameSpaces) {
Map<String, Element> name2elementMap = null;
if (!getCacheMap().get(targetFile).containsKey(elementName)) {
name2elementMap = new HashMap<>();
getCacheMap().get(targetFile).put(elementName, name2elementMap);
}
else {
name2elementMap = (Map<String, Element>) getCacheMap().get(targetFile).get(elementName);
}
final List<Element> elements = HelperUtil.getXpathResult(rootDocument, xpath, Element.class, nameSpaces);
for (final Element element : elements) {
final Attribute attribute = element.getAttribute("name");
if (attribute != null) {
name2elementMap.put(attribute.getValue(), element);
}
}
}
// TODO: optimize Xpath
@SuppressWarnings("unchecked")
protected void populate_AllElements_referred_by_hrefURIFragments(
File targetFile,
Document rootDocument,
Map<File, Document> fileName2documentMap,
String HREF_URIFRAGMENT_ELEMENT_REFS_ATRIBUTES,
String HREF_URIFRAGMENT_ELEMENT) {
Map<File, Map<String, Map<String, List<Attribute>>>> reffile2uriFragment2schedulerRefAttribsMap =
(Map<File, Map<String, Map<String, List<Attribute>>>>) getCacheMap().get(targetFile).get(HREF_URIFRAGMENT_ELEMENT_REFS_ATRIBUTES);
Set<File> keySet = reffile2uriFragment2schedulerRefAttribsMap.keySet();
/*- Result: gloabl uri fragment & JDOM Element mapping */
Map<String, Element> allElements_referred_by_URIFragments = new HashMap<>();
getCacheMap().get(targetFile).put(HREF_URIFRAGMENT_ELEMENT, allElements_referred_by_URIFragments);
/*- ===========new code ==============*/
for (File referencedFile : keySet) {
/*- Fetching the corresponding Document object belonging to the referencedFile [Note: all Xpath's should be applied on this document ] */
Document targetDocument = fileName2documentMap.get(referencedFile);
/*-Below table contains Row as: GlobalURI Fragment, Column as : local URI Fragment, value as: List of attributes having global URI fragment */
Map<String, Map<String, List<Attribute>>> table = reffile2uriFragment2schedulerRefAttribsMap.get(referencedFile);
/*- temporary Map to store key as local URIFragment and Vale as global URI Fragment*/
final Map<String, String> localUriFragment2globalUriFragmentMap = new HashMap<>();
/*- temporary Map to store key as local URIFragment and Vale as Xpath*/
final Map<String, String> localUriFragment2XpathMap = new HashMap<>();
/*- temporary Map to store key as Xpath and Vale as JDOM Elements which are obtained as result of this Xpath*/
Map<String, List<Element>> xpath2ElementsMap = new HashMap<>();
for (final Entry<String, Map<String, List<Attribute>>> entry : table.entrySet()) {
/*- rowkey is global URI fragment */
final String row_globalURI = entry.getKey();
final Map<String, List<Attribute>> rowMap = entry.getValue();
final Set<String> columns = rowMap.keySet();
if (columns != null && !columns.isEmpty()) {
// As there is one to one mapping between Global URI Fragments and local URI fragment associated to
// it. Pick the first element
for (final String column_localURI : columns) {
/*- column_localURI is local URI fragment (i.e. without file name information) */
localUriFragment2globalUriFragmentMap.put(column_localURI, row_globalURI);
/*- column_localURI is local URI fragment (i.e. without file name information) & value is the corresponding Xpath*/
localUriFragment2XpathMap.put(column_localURI, getXpathString(column_localURI));
}
}
}
/*- Bulk operation applied to fetch the JDOM Element's to improve the performance */
final BulkXpathOperation bulkXpathOperation = new BulkXpathOperation();
/*- supplying targetDcoument (JDOM Document object), Xpath's (obtained from local URI fragments) and helper class object */
xpath2ElementsMap = bulkXpathOperation.invokeXpath(targetDocument, localUriFragment2XpathMap.values());
/*- now populating the resultsMap with the required data : i.e. Global URI fragment & JDOM Elements belonging to it */
for (Entry<String, String> entry : localUriFragment2XpathMap.entrySet()) {
String localUri = entry.getKey();
String xpath = entry.getValue();
String globalUri = localUriFragment2globalUriFragmentMap.get(localUri);
List<Element> elements = xpath2ElementsMap.get(xpath);
if (!elements.isEmpty()) {
allElements_referred_by_URIFragments.put(globalUri, elements.get(0));
} else {
LOGGER.error("Element could not be found for URI : {}", globalUri);
}
}
}
}
}