/** | |
******************************************************************************** | |
* 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); | |
} | |
} | |
} | |
} | |
} |