/******************************************************************************* * Copyright (c) 2010 Herman Lee. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Herman Lee - initial API and implementation ******************************************************************************/ package ca.uwaterloo.gsd.fsml.xmlMappingInterpreter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.NoSuchElementException; import java.util.StringTokenizer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; import org.eclipse.wst.xml.core.internal.document.AttrImpl; import org.eclipse.wst.xml.core.internal.document.DocumentImpl; import org.eclipse.wst.xml.core.internal.document.ElementImpl; import org.eclipse.wst.xml.core.internal.document.TextImpl; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; import org.eclipse.wst.xml.core.internal.provisional.format.FormatProcessorXML; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import ca.uwaterloo.gsd.fsml.core.Cause; import ca.uwaterloo.gsd.fsml.core.FSMLMappingException; import ca.uwaterloo.gsd.fsml.core.FSMLMappingInterpreter; import ca.uwaterloo.gsd.fsml.core.MarkerDescriptor; import ca.uwaterloo.gsd.fsml.core.Markers; import ca.uwaterloo.gsd.fsml.core.Queries; import ca.uwaterloo.gsd.fsml.ecore.FSMLEcoreUtil; import ca.uwaterloo.gsd.fsml.stats.Stats; import ca.uwaterloo.gsd.fsml.sync.ClassSyncItem; import ca.uwaterloo.gsd.fsml.sync.StructuralFeatureSyncItem; public class XMLMappingInterpreter extends FSMLMappingInterpreter { private static final String QUERY_XML_ELEMENTS = "xmlElements"; public static final String QUERY_XML_DOCUMENT = "xmlDocument"; public static final String QUERY_XML_ELEMENT = "xmlElement"; public static final String QUERY_XML_ATTRIBUTE = "xmlAttribute"; @Override public String getDescription() { return "XML Annotation Interpreter"; } public String[] getContextAnnotations() { return new String[] { QUERY_XML_ELEMENT, QUERY_XML_DOCUMENT, "project" }; } @Override public String[] getQueryAnnotations() { return new String[] { QUERY_XML_ELEMENTS, QUERY_XML_ATTRIBUTE, "valueEqualsTo", "xmlElementValue", "xmlElementValueEqualsString", "noXMLElement","documentPath" }; } public static final String id = "xml"; public HashMap<EObject, Node> feature2Node = new HashMap<EObject, Node>(); public HashMap<String, Node> feature2Node4Forward = new HashMap<String, Node>(); public HashMap<EObject, IResource> feature2IResource = new HashMap<EObject, IResource>(); public HashMap<String, IResource> feature2IResource4Forward = new HashMap<String, IResource>(); public HashMap<EObject, Document> feature2IDOMDocument = new HashMap<EObject, Document>(); public HashMap<String, Document> feature2IDOMDocument4Forward = new HashMap<String, Document>(); @Override public boolean canForwardObjectUsingQueryMapping(EReference reference) { //TODO: support other mapping types if (reference.getEAnnotation(QUERY_XML_ELEMENTS) != null) { return true; } else { return false; } } @Override public boolean canHandleContext(Class contextClass) { return contextClass != null && ( Node.class.isAssignableFrom(contextClass)); } @Override public void associateContext(EObject object, Object context) { if (context instanceof Node){ feature2Node.put(object, (Node)context); feature2Node4Forward.put(FSMLEcoreUtil.getFSMLId(object, null), (Node)context); } } @Override public boolean canAssociateContext(EObject eObject) { if (eObject.eClass().getEAnnotation(QUERY_XML_ELEMENT) != null|| eObject.eClass().getEAnnotation(QUERY_XML_DOCUMENT) != null ) { return true; } else { return false; } } @Override public void associateContext(int start, int end, EObject eObject) { EObject contextDocument= FSMLEcoreUtil.retrieveContextElement(eObject,QUERY_XML_DOCUMENT); IResource resource = feature2IResource.get(contextDocument); if (resource==null){ EObject projectElement = FSMLEcoreUtil.retrieveContextElement( eObject, "project"); IProject project = (IProject) Queries.INSTANCE.getContext( projectElement, IProject.class, true); String xmlDocPath = contextDocument.eClass().getEAnnotation(QUERY_XML_DOCUMENT).getDetails().get("path"); IDOMModel xmlModel; try { xmlModel = (IDOMModel) StructuredModelManager.getModelManager() .getModelForEdit(project.getFile(xmlDocPath)); feature2IDOMDocument.put(contextDocument, xmlModel.getDocument()); feature2IDOMDocument4Forward.put(FSMLEcoreUtil.getFSMLId(contextDocument, null), xmlModel.getDocument()); resource = project.getFile(xmlDocPath); feature2IResource.put(contextDocument, project.getFile(xmlDocPath)); feature2IResource4Forward.put(FSMLEcoreUtil.getFSMLId(contextDocument, null), project.getFile(xmlDocPath)); } catch (IOException e) { e.printStackTrace(); } catch (CoreException e) { e.printStackTrace(); } } IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(resource.getRawLocation()); IDOMModel modelForEdit; try { modelForEdit = (IDOMModel) StructuredModelManager.getModelManager() .getModelForEdit(file); IndexedRegion indexedRegion = modelForEdit.getIndexedRegion(start); if (indexedRegion instanceof Node){ feature2Node.put(eObject, (Node)indexedRegion); feature2Node4Forward.put(FSMLEcoreUtil.getFSMLId(eObject, null), (Node)indexedRegion); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (CoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public boolean forwardFeatureRepresentedAsClass( ClassSyncItem classSyncItem, IProgressMonitor progressMonitor) throws FSMLMappingException { // TODO Auto-generated method stub return super.forwardFeatureRepresentedAsClass(classSyncItem, progressMonitor); } @Override public boolean forwardFeatureRepresentedAsAttribute( StructuralFeatureSyncItem featureSyncItem, IProgressMonitor progressMonitor) throws FSMLMappingException { EStructuralFeature feature = featureSyncItem.getStructuralFeature(); EObject container = ((ClassSyncItem) featureSyncItem.eContainer()).getModel() != null ? ((ClassSyncItem) featureSyncItem.eContainer()).getModel(): ((ClassSyncItem) featureSyncItem.eContainer()).getCode(); Element containerNode = (Element) feature2Node4Forward .get(FSMLEcoreUtil.getFSMLId(container, null)); EObject contextDocument = FSMLEcoreUtil.retrieveContextElement( container, QUERY_XML_DOCUMENT); IResource resource = feature2IResource4Forward.get(FSMLEcoreUtil .getFSMLId(contextDocument, null)); IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(resource.getRawLocation()); IDOMModel modelForEdit; Document contextDocumentNode = feature2IDOMDocument4Forward .get(FSMLEcoreUtil.getFSMLId(contextDocument, null)); try { modelForEdit = (IDOMModel) StructuredModelManager.getModelManager() .getModelForEdit(file); modelForEdit.aboutToChangeModel(); DocumentImpl document = (DocumentImpl) modelForEdit.getDocument(); AttrImpl newAttributeNode = null; EAnnotation annotation = feature .getEAnnotation(QUERY_XML_ATTRIBUTE); if (annotation.getDetails().get("name") != null) { newAttributeNode = (AttrImpl) document .createAttribute(annotation.getDetails().get("name")); newAttributeNode.setValue((String) container.eGet(feature)); } else { newAttributeNode = (AttrImpl) document.createAttribute(feature .getName()); while (container.eGet(feature)==null){ container.eSet(feature,FSMLEcoreUtil.getAttributeValueFromAttributeValueWizard((EAttribute)feature)); } newAttributeNode.setValue((String) container.eGet(feature)); } containerNode.setAttributeNode(newAttributeNode); FormatProcessorXML formatter = new FormatProcessorXML(); formatter.formatNode(containerNode); modelForEdit.save(); modelForEdit.changedModel(); modelForEdit.releaseFromEdit(); MarkerDescriptor markerDescriptor = Markers .createMarkerDescriptor(resource); markerDescriptor.setAttributes(feature, newAttributeNode .getStartOffset(), newAttributeNode.getEndOffset()); markerDescriptor.create(container); } catch (IOException e) { throw new FSMLMappingException(Cause.UNKNOWN, "Error in XML Forward, IOException"); } catch (CoreException e) { throw new FSMLMappingException(Cause.UNKNOWN, "Error in XML Forward, CoreException"); } return true; } @Override public boolean forwardFeatureRepresentedAsReference( ClassSyncItem classSyncItem, IProgressMonitor progressMonitor) throws FSMLMappingException { EObject elementToForward = classSyncItem.getModel() != null ? classSyncItem .getModel() : classSyncItem.getCode(); // in case a class isn't associated with an xml element EObject contextElement = FSMLEcoreUtil.retrieveContextElement( elementToForward, QUERY_XML_ELEMENT); EObject contextDocument = FSMLEcoreUtil.retrieveContextElement( elementToForward, QUERY_XML_DOCUMENT); IResource resource = feature2IResource4Forward.get(FSMLEcoreUtil .getFSMLId(contextDocument, null)); IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(resource.getRawLocation()); IDOMModel modelForEdit; try { Document contextDocumentNode = feature2IDOMDocument4Forward .get(FSMLEcoreUtil.getFSMLId(contextDocument, null)); modelForEdit = (IDOMModel) StructuredModelManager.getModelManager() .getModelForEdit(file); Node contextElementNode = feature2Node4Forward.get(FSMLEcoreUtil .getFSMLId(contextElement.eContainer(), null)); // get the path of the reference String path = contextElement.eContainingFeature().getEAnnotation( QUERY_XML_ELEMENTS).getDetails().get("path"); //start editing the xml file modelForEdit.aboutToChangeModel(); DocumentImpl document = (DocumentImpl) modelForEdit .getDocument(); if (!path.equals("/")) { String elementToCreate = null; if (path.indexOf("/") == -1) { elementToCreate = path; } else { elementToCreate = path.substring(path.lastIndexOf("/") + 1, path.length()); path = path.substring(0, path.lastIndexOf("/")); // cut out the last part of the path since that is for the new node StringTokenizer tokenizer = new StringTokenizer(path, "/"); Node currentNode = null; ArrayList<Node> result = new ArrayList<Node>(); Node lastPathElementNodeFound = contextElementNode; StringBuffer partsOfPathFoundInCode = new StringBuffer(); if (path.charAt(0) != '/') { // it's a relative path Node parent = contextElementNode; currentNode = parent.getFirstChild(); } else { // it's an absolute path // we want to check the first token to see whether the // name is the same as root node's name // if not, just return an empty vector // if so, we can move on to the next token in the xpath currentNode = contextDocumentNode; if (!currentNode.getNodeName().equals( tokenizer.nextToken())) { throw new FSMLMappingException( Cause.MODEL_NAVIGATION_ERROR, "invalid xml path"); } currentNode = currentNode.getFirstChild(); } String currentToken = tokenizer.nextToken(); while (currentNode != null) { if (currentNode instanceof ElementImpl) { if (currentToken == null) { contextElementNode = null; } if (currentNode.getNodeName().equals(currentToken)) { // proceed to produce the nodeList String currentTokenValue = currentToken; try { lastPathElementNodeFound = currentNode; partsOfPathFoundInCode.append(currentToken+"/"); currentToken = tokenizer.nextToken(); // pre-get the next token to see if we are in the last token } catch (NoSuchElementException e) { // reached the end of the xpath result.add(currentNode); currentToken = currentTokenValue; // look for sibling currentNode = currentNode.getNextSibling(); continue; } currentNode = currentNode.getFirstChild(); continue; } } currentNode = currentNode.getNextSibling(); } if (result.size()==0) { //couldn't find the elements specified in path //create the xml elements tokenizer = new StringTokenizer(path.replaceAll(partsOfPathFoundInCode.toString(), ""), "/"); while (tokenizer.hasMoreTokens()) { ElementImpl newElementNode = (ElementImpl) document .createElement(tokenizer.nextToken()); lastPathElementNodeFound.appendChild(newElementNode); lastPathElementNodeFound=newElementNode; } contextElementNode = lastPathElementNodeFound; } else { contextElementNode = result.get(0); } } ElementImpl newElementNode = (ElementImpl) document .createElement(elementToCreate); feature2Node4Forward.put(FSMLEcoreUtil.getFSMLId( elementToForward, null), newElementNode); contextElementNode.appendChild(newElementNode); FormatProcessorXML formatter = new FormatProcessorXML(); formatter.formatNode(contextElementNode); modelForEdit.save(); modelForEdit.changedModel(); modelForEdit.releaseFromEdit(); //set the markers MarkerDescriptor markerDescriptor = Markers .createMarkerDescriptor(resource); markerDescriptor.setAttributes(null, newElementNode .getStartOffset(), newElementNode.getEndOffset()); markerDescriptor.create(elementToForward); } } catch (IOException e1) { throw new FSMLMappingException(Cause.UNKNOWN, "Error in XML Forward, IOException"); } catch (CoreException e1) { throw new FSMLMappingException(Cause.UNKNOWN, "Error in XML Forward, CoreException"); } return true; } public boolean canCreateChildrenForDefaultQuery(EClass eClass) { return FSMLEcoreUtil.getEAnnotation(eClass, QUERY_XML_DOCUMENT) != null; } public boolean createChildrenForDefaultQuery(EObject element, EReference feature, EClass referenceType, IProgressMonitor progressMonitor) throws FSMLMappingException { EAnnotation annotation = FSMLEcoreUtil.getEAnnotation(referenceType, QUERY_XML_DOCUMENT); if (annotation != null) { EObject projectElement = FSMLEcoreUtil.retrieveContextElement( element, "project"); IProject project = (IProject) Queries.INSTANCE.getContext( projectElement, IProject.class, true); String pathName = (String) annotation.getDetails().get("path"); String fileName = (String) annotation.getDetails().get("fileName"); //ResourcesPlugin.getWorkspace().getRoot().getFile(path) if ((pathName == null || pathName.isEmpty()) &&(fileName == null || fileName.isEmpty())) return false; ArrayList<IFile> xmlDocumentsToCreate = new ArrayList<IFile>(); if (pathName != null){ IFile fileFromPath = project.getFile(pathName); if (fileFromPath.exists()){ xmlDocumentsToCreate.add(fileFromPath); } } else{ try{ for (IResource resource : project.members()) { if (resource instanceof IFile && resource.getName().equalsIgnoreCase(fileName)){ xmlDocumentsToCreate.add((IFile)resource); } else if (resource instanceof IFolder){ this.searchFolderForFile((IFolder)resource,fileName,xmlDocumentsToCreate); } } } catch(CoreException e){ return false; } } for (IFile file : xmlDocumentsToCreate) { IDOMModel xmlModel; try { xmlModel = (IDOMModel) StructuredModelManager.getModelManager() .getModelForEdit(file); } catch (Exception e) { return false; } IDOMDocument xmlDocument = xmlModel.getDocument(); EObject child = EcoreUtil.create(referenceType); EAnnotation firstXMLDocumentElement = FSMLEcoreUtil.getEAnnotation( referenceType, QUERY_XML_ELEMENT); String firstXMLDocumentElementName = null; if (firstXMLDocumentElement != null) firstXMLDocumentElementName = (String) firstXMLDocumentElement .getDetails().get("name"); Node rootElement = xmlDocument.getFirstChild(); while (rootElement!=null &&(!(rootElement instanceof Element) || !rootElement.getNodeName().equals( firstXMLDocumentElementName))) { rootElement = rootElement.getNextSibling(); } if (rootElement!=null) { feature2Node.put(child, rootElement); } else { return false; } if (feature.isMany()) ((EList) element.eGet(feature)).add(child); else element.eSet(feature, child); feature2IDOMDocument.put(child, xmlDocument); feature2IDOMDocument4Forward.put(FSMLEcoreUtil.getFSMLId(child, null), xmlDocument); if (file.exists()) { feature2IResource.put(child, file); feature2IResource4Forward.put(FSMLEcoreUtil.getFSMLId(child, null), file); if (rootElement instanceof ElementImpl){ MarkerDescriptor markerDescriptor = Markers .createMarkerDescriptor(file); markerDescriptor.setAttributes(null, ((ElementImpl)rootElement) .getStartOffset(), ((ElementImpl)rootElement).getEndOffset()); markerDescriptor.create(child); } } if (reverseFeatureRepresentedAsClass(child, progressMonitor)) { Stats.INSTANCE.logFeatureInstance(element, feature, annotation); } if (rootElement!=null){ feature2Node4Forward.put(FSMLEcoreUtil.getFSMLId(child, null), rootElement); } } return true; } return false; } private void searchFolderForFile(IFolder folder, String fileName, ArrayList<IFile> xmlDocumentsToCreate) { try{ for (IResource resource : folder.members()) { if (resource instanceof IFile && resource.getName().equalsIgnoreCase(fileName)){ xmlDocumentsToCreate.add((IFile)resource); } else if (resource instanceof IFolder){ this.searchFolderForFile((IFolder)resource,fileName,xmlDocumentsToCreate); } } } catch (CoreException e){ return; } } @Override public boolean reverseFeatureRepresentedAsAttribute(EObject element, EAttribute attribute, IProgressMonitor progressMonitor) { EAnnotation annotation3 = attribute.getEAnnotation(QUERY_XML_ATTRIBUTE); if (annotation3 != null) { EObject aux = FSMLEcoreUtil.retrieveContextElement(element, QUERY_XML_ELEMENT); ElementImpl currentNode = (ElementImpl) feature2Node.get(aux); EObject documentElement = FSMLEcoreUtil.retrieveContextElement(aux, QUERY_XML_DOCUMENT); IResource resource = feature2IResource.get(documentElement); String attributeName = (String) annotation3.getDetails() .get("name"); if (attributeName == null) { // i.e. if the name detail is not // present, just use the attribute's // name attributeName = attribute.getName(); } if (currentNode.getAttributes().getNamedItem(attributeName) == null) { return false; } String attributeValue = currentNode.getAttributes().getNamedItem( attributeName).getNodeValue(); element.eSet(attribute, attributeValue); MarkerDescriptor markerDescriptor = Markers .createMarkerDescriptor(resource); AttrImpl attrImpl = (AttrImpl) currentNode.getAttributes() .getNamedItem(attributeName); markerDescriptor.setAttributes(attribute, attrImpl.getStartOffset(), attrImpl.getEndOffset()); markerDescriptor.create(element); Stats.INSTANCE.logScatteringAndTangling(element, attribute, null, "<" + currentNode.getNodeName() + ">()"); Stats.INSTANCE.logScatteringAndTangling(element, attribute, null, resource.getProjectRelativePath().toString()); return true; } annotation3 = attribute.getEAnnotation("xmlElementValue"); if (annotation3 != null) { EObject aux = FSMLEcoreUtil.retrieveContextElement(element, QUERY_XML_ELEMENT); ElementImpl currentNode = (ElementImpl) feature2Node.get(aux); EObject documentElement = FSMLEcoreUtil.retrieveContextElement(aux, QUERY_XML_DOCUMENT); IResource resource = feature2IResource.get(documentElement); if (currentNode == null || !(currentNode.getFirstChild() instanceof TextImpl)) { return false; } TextImpl childNode = (TextImpl) currentNode.getFirstChild(); String nodeValue = childNode.getData(); element.eSet(attribute, nodeValue); MarkerDescriptor markerDescriptor = Markers .createMarkerDescriptor(resource); markerDescriptor.setAttributes(null, currentNode.getStartOffset(), currentNode.getEndOffset()); markerDescriptor.create(element); Stats.INSTANCE.logScatteringAndTangling(element, attribute, null, "<" + currentNode.getNodeName() + ">()"); Stats.INSTANCE.logScatteringAndTangling(element, attribute, null, resource.getProjectRelativePath().toString()); return true; } annotation3 = attribute.getEAnnotation("xmlElementValueEqualsString"); if (annotation3 != null) { String stringBeingSearchedFor = (String) annotation3.getDetails() .get("StringToSearchFor"); EObject aux = FSMLEcoreUtil.retrieveContextElement(element, QUERY_XML_ELEMENT); ElementImpl currentNode = (ElementImpl) feature2Node.get(aux); EObject documentElement = FSMLEcoreUtil.retrieveContextElement(aux, QUERY_XML_DOCUMENT); IResource resource = feature2IResource.get(documentElement); if (!(currentNode.getFirstChild() instanceof TextImpl)) { return false; } TextImpl childNode = (TextImpl) currentNode.getFirstChild(); String nodeValue = childNode.getData(); if (nodeValue.equalsIgnoreCase(stringBeingSearchedFor)) { element.eSet(attribute, true); } else { element.eSet(attribute, false); } MarkerDescriptor markerDescriptor = Markers .createMarkerDescriptor(resource); markerDescriptor.setAttributes(null, currentNode.getStartOffset(), currentNode.getEndOffset()); markerDescriptor.create(element); Stats.INSTANCE.logScatteringAndTangling(element, attribute, null, "<" + currentNode.getNodeName() + ">()"); Stats.INSTANCE.logScatteringAndTangling(element, attribute, null, resource.getProjectRelativePath().toString()); return true; } annotation3 = attribute.getEAnnotation("noXMLElement"); if (annotation3 != null) { String path = (String) annotation3.getDetails().get("path"); EObject aux = FSMLEcoreUtil.retrieveContextElement(element, QUERY_XML_ELEMENT); ElementImpl currentNode = (ElementImpl) feature2Node.get(aux); EObject documentElement = FSMLEcoreUtil.retrieveContextElement(aux, QUERY_XML_DOCUMENT); IResource resource = feature2IResource.get(documentElement); ArrayList<Node> resultVector = findChildGivenPath(aux, path); if (resultVector.isEmpty()) { element.eSet(attribute, true); } else { element.eSet(attribute, false); } MarkerDescriptor markerDescriptor = Markers .createMarkerDescriptor(resource); markerDescriptor.setAttributes(null, currentNode.getStartOffset(), currentNode.getEndOffset()); markerDescriptor.create(element); return true; } annotation3 = attribute.getEAnnotation("documentPath"); if (annotation3 != null) { EObject documentElement = FSMLEcoreUtil.retrieveContextElement(element,QUERY_XML_DOCUMENT); IResource resource = feature2IResource.get(documentElement); element.eSet(attribute, resource.getFullPath().toString()); return true; } return false; } private ArrayList<Node> findChildGivenPath(EObject aux, String path) { // skip TextImpl and DocumentTypeImpl // or just try to look for the next ElementImpl ArrayList<Node> result = new ArrayList<Node>(); if (path == null){ return result; } StringTokenizer tokenizer = new StringTokenizer(path, "/"); Node currentNode = null; if (path.charAt(0) != '/') { // it's a relative path Node parent = feature2Node.get(aux); if (parent==null) { return result; } currentNode = parent.getFirstChild(); } else { // it's an absolute path EObject documentElement = FSMLEcoreUtil.retrieveContextElement(aux, QUERY_XML_DOCUMENT); Node root = feature2Node.get(documentElement); // we want to check the first token to see whether the name is the // same as root node's name // if not, just return an empty vector // if so, we can move on to the next token in the xpath currentNode = root; if (!currentNode.getNodeName().equals(tokenizer.nextToken())) { return result; } currentNode = currentNode.getFirstChild(); } String currentToken = tokenizer.nextToken(); while (currentNode != null) { if (currentNode instanceof ElementImpl) { if (currentToken == null) { return null; } if (currentNode.getNodeName().equals(currentToken)) { // proceed to produce the nodeList String currentTokenValue = currentToken; try { currentToken = tokenizer.nextToken(); // pre-get the // next token to // see if we are // in the last // token } catch (NoSuchElementException e) { // reached the end of the xpath result.add(currentNode); currentToken = currentTokenValue; // look for sibling currentNode = currentNode.getNextSibling(); continue; } currentNode = currentNode.getFirstChild(); continue; } } currentNode = currentNode.getNextSibling(); } // return result when there are no more siblings return result; } @Override public boolean reverseFeatureRepresentedAsReference(EObject element, EReference reference, EClass referenceType, IProgressMonitor progressMonitor) throws FSMLMappingException { EAnnotation annotation = reference.getEAnnotation(QUERY_XML_ELEMENTS); if (annotation != null) { String path = (String) annotation.getDetails().get("path"); EObject aux = FSMLEcoreUtil.retrieveContextElement(element, QUERY_XML_ELEMENT); ArrayList<Node> resultVector = findChildGivenPath(aux, path); if (resultVector.isEmpty()){ path = (String) annotation.getDetails().get("path2"); resultVector = findChildGivenPath(aux, path); } // let's sort the nodes Object[] result = resultVector.toArray(); // { class NodeComparator implements Comparator { public int // compare(Object o1, Object o2) { ElementImpl e1 = (ElementImpl) // o1; ElementImpl e2 = (ElementImpl) o2; // // //TODO: need to modify this hard-coding // // if (e1.getAttributes().getNamedItem("name") == null // || e2.getAttributes().getNamedItem("name") == null) { // return (e1.getAttributes().getNamedItem("path") // .getNodeValue()).compareTo(e2 // .getAttributes().getNamedItem("path") // .getNodeValue()); // } else { // return (e1.getAttributes().getNamedItem("name") // .getNodeValue()).compareTo(e2 // .getAttributes().getNamedItem("name") // .getNodeValue()); // } // } // } // NodeComparator comparator = new NodeComparator(); // Arrays.sort(result, comparator); // } for (int i = 0; i < result.length; i++) { EObject child = EcoreUtil.create(referenceType); feature2Node.put(child, (Node) result[i]); if (reference.isMany()) { ((EList) element.eGet(reference)).add(child); } else { element.eSet(reference, child); } reverseFeatureRepresentedAsClass(child, progressMonitor); feature2Node4Forward.put(FSMLEcoreUtil.getFSMLId(child, null), (Node) result[i]); EObject documentElement = FSMLEcoreUtil.retrieveContextElement( aux, QUERY_XML_DOCUMENT); IResource resource = feature2IResource.get(documentElement); ElementImpl elementImpl = (ElementImpl) result[i]; MarkerDescriptor markerDescriptor = Markers .createMarkerDescriptor(resource); markerDescriptor.setAttributes(null, elementImpl .getStartOffset(), elementImpl.getEndOffset()); markerDescriptor.create(child); Stats.INSTANCE.logScatteringAndTangling(element, reference, null, resource.getProjectRelativePath().toString()); } if (result.length>0) { return true; } else { return false; } } return false; } }