package com.openMap1.mapper.actions;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.w3c.dom.Element;
import com.openMap1.mapper.core.MapperException;
import com.openMap1.mapper.util.ModelUtil;
import com.openMap1.mapper.util.XMLUtil;
public class MakeEcoreFromXMIActionDelegate
implements IObjectActionDelegate{
public IWorkbenchPart targetPart; // where this action was invoked from
public ISelection selection;
private Hashtable<String,EClass> allClasses;
private Hashtable<String,Element> assocEls;
public void run(IAction action) {
String projectName = getSelectedProject().getName();
try {
// (1) find the location of the selected XMI file
IFile XMIFile = getSelectedFile();
String xmiFilePath = XMIFile.getLocation().toString();
// System.out.println("XMI file location: " + xmiFilePath);
// (2) Open the XMI as an XML file
Element XMIRoot = XMLUtil.getRootElement(xmiFilePath);
if (XMIRoot == null) throw new MapperException("Cannot open XMI file at " + xmiFilePath);
// (3) create the Ecore model
EPackage topPackage = makeEcoreModel(XMIRoot);
//the Ecore model is stored in the ClassModel folder of the same project as the selected XMI file
String ecoreFolderPath = "platform:/resource/" + projectName + "/ClassModel/";
String fileName = XMIFile.getName();
String ecoreModelLocation = ecoreFolderPath + fileName.substring(0,fileName.length()-3) + "ecore";
ModelUtil.savePackage(ecoreModelLocation, topPackage);
}
catch (Exception ex)
{
ex.printStackTrace();
showMessage("Failed to convert XMI file to Ecore model: " + ex.getMessage());
}
}
/**
*
* @param XMIRoot
* @return
* @throws MapperException
*/
private EPackage makeEcoreModel(Element XMIRoot) throws MapperException
{
allClasses = new Hashtable<String,EClass>() ;
assocEls = new Hashtable<String,Element>() ;
Element modelEl = XMLUtil.firstNamedChild(XMIRoot, "Model");
if (modelEl == null) throw new MapperException("Failed to find top 'Model' element");
Vector<Element> topPackages = XMLUtil.namedChildElements(modelEl, "packagedElement");
if (topPackages.size() != 1) throw new MapperException("Found " + topPackages.size() + " top packages");
Element topPackageEl = topPackages.get(0);
EPackage topPackage = EcoreFactory.eINSTANCE.createEPackage();
// make all packages and classes, with their attributes
makeClassesAndSubPackages(topPackage,topPackageEl);
// make all two-ended associations
for (Enumeration<Element> en = assocEls.elements();en.hasMoreElements();)
addTwoEndedAssociation(en.nextElement());
// make all associations
addOneEndedAssociations(topPackageEl);
return topPackage;
}
/**
* create all classes in this package, and recursively create sub-packages and their classes
* @param thePackage
* @param thePackageEl
*/
private void makeClassesAndSubPackages(EPackage thePackage,Element thePackageEl) throws MapperException
{
// name the package
String packageName = thePackageEl.getAttribute("name");
thePackage.setName(packageName);
// add all classes in the package, and recursively add sub-packages
for (Iterator<Element> it = XMLUtil.namedChildElements(thePackageEl, "packagedElement").iterator(); it.hasNext();)
{
Element next = it.next();
String type = next.getAttribute("xmi:type");
if (type.equals("uml:Class"))
{
addClass(thePackage,next);
}
// store associations for the next pass
if (type.equals("uml:Association"))
{
String assocId = next.getAttribute("xmi:id");
assocEls.put(assocId, next);
}
if (type.equals("uml:Package"))
{
EPackage nextPackage = EcoreFactory.eINSTANCE.createEPackage();
thePackage.getESubpackages().add(nextPackage);
makeClassesAndSubPackages(nextPackage, next);
}
}
}
/**
*
* @param assocEl
*/
private void addTwoEndedAssociation(Element assocEl) throws MapperException
{
Vector<Element> ends = XMLUtil.namedChildElements(assocEl, "ownedEnd");
if (ends.size() == 2)
{
//create the two EReferences
EReference ref0 = makeEReference(ends.get(0));
EReference ref1 = makeEReference(ends.get(1));
// set the owning class of each EReference
((EClass)ref0.getEType()).getEStructuralFeatures().add(ref1);
((EClass)ref1.getEType()).getEStructuralFeatures().add(ref0);
// make them opposites of each other
ref0.setEOpposite(ref1);
}
}
/**
*
* @param theClass
* @param assocEl
* @throws MapperException
*/
private void addOneEndedAssociation(EClass theClass,Element assocEl) throws MapperException
{
Vector<Element> ends = XMLUtil.namedChildElements(assocEl, "ownedEnd");
if (ends.size() == 1)
{
//create the EReference
EReference ref = makeEReference(ends.get(0));
theClass.getEStructuralFeatures().add(ref);
}
}
/**
*
* @param ownedEnd
* @return an EReference made from it
* @throws MapperException
*/
private EReference makeEReference(Element ownedEnd) throws MapperException
{
EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setName(ownedEnd.getAttribute("name"));
String typeId = XMLUtil.firstNamedChild(ownedEnd, "type").getAttribute("xmi:idref");
EClass target = allClasses.get(typeId);
if (target == null) throw new MapperException("Cannot find target class with id " + typeId);
ref.setEType(target);
Element lower = XMLUtil.firstNamedChild(ownedEnd, "lowerValue");
if (lower != null) ref.setLowerBound(new Integer(lower.getAttribute("value")).intValue());
Element upper = XMLUtil.firstNamedChild(ownedEnd, "upperValue");
if (upper != null) ref.setUpperBound(new Integer(upper.getAttribute("value")).intValue());
return ref;
}
/**
* add associations and superclass relations, recursively going down through packages
* @param thePackage
* @param thePackageEl
*/
private void addOneEndedAssociations(Element thePackageEl) throws MapperException
{
for (Iterator<Element> it = XMLUtil.namedChildElements(thePackageEl, "packagedElement").iterator(); it.hasNext();)
{
Element next = it.next();
String type = next.getAttribute("xmi:type");
if (type.equals("uml:Class"))
{
secondPassClass(next);
}
if (type.equals("uml:Package"))
{
addOneEndedAssociations(next);
}
}
}
/**
* add a class and its attributes to a package
* @param thePackage
* @param classEl
* @throws MapperException
*/
private void addClass(EPackage thePackage,Element classEl) throws MapperException
{
String id = classEl.getAttribute("xmi:id");
EClass theClass = EcoreFactory.eINSTANCE.createEClass();
theClass.setName(classEl.getAttribute("name"));
allClasses.put(id, theClass);
thePackage.getEClassifiers().add(theClass);
for (Iterator<Element> it = XMLUtil.namedChildElements(classEl, "ownedAttribute").iterator(); it.hasNext();)
{
Element attEl = it.next();
if (attEl.getAttribute("association").equals(""))
{
EAttribute theAtt = EcoreFactory.eINSTANCE.createEAttribute();
theAtt.setName(attEl.getAttribute("name"));
theClass.getEStructuralFeatures().add(theAtt);
}
}
}
/**
*
* @param classEl
* @throws MapperException
*/
private void secondPassClass(Element classEl) throws MapperException
{
String id = classEl.getAttribute("xmi:id");
EClass theClass = allClasses.get(id);
if (theClass == null) throw new MapperException("Cannot find class with id " + id);
// find all superclasses of the class
for (Iterator<Element> it = XMLUtil.namedChildElements(classEl, "generalization").iterator(); it.hasNext();)
{
Element genEl = it.next();
String genId = genEl.getAttribute("general");
EClass genClass = allClasses.get(genId);
if (genClass == null) System.out.println("Cannot find superclass with id " + genId + " for class " + theClass.getName());
else theClass.getESuperTypes().add(genClass);
}
// add one-ended associations
for (Iterator<Element> it = XMLUtil.namedChildElements(classEl, "ownedAttribute").iterator(); it.hasNext();)
{
Element attEl = it.next();
String assocId = attEl.getAttribute("association");
if (!assocId.equals(""))
{
Element assocEl = assocEls.get(assocId);
if (assocEl == null) {} //throw new MapperException("Cannot find association with id " + assocId);
else addOneEndedAssociation(theClass,assocEl);
}
}
}
//----------------------------------------------------------------------------------------------
// Eclipse plumbing
//----------------------------------------------------------------------------------------------
/**
* @return the project in which the selected mif file is located
*/
protected IProject getSelectedProject()
{
if (getSelectedFile() != null) return getSelectedFile().getProject();
return null;
}
@Override
public void selectionChanged(IAction action, ISelection selection) {
this.selection = selection;
}
protected void showMessage(String title, String message) {
MessageDialog.openInformation(
targetPart.getSite().getShell(),
title,
message);
}
/**
* default if you can't be bothered to make up a message title
* @param message
*/
protected void showMessage(String message)
{showMessage("Error",message);}
//cache the target part so we can get the shell
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
this.targetPart = targetPart;
}
/**
* @return the file containing the selected XMI
*/
protected IFile getSelectedFile()
{
if (selection instanceof IStructuredSelection)
{
Object el = ((IStructuredSelection)selection).getFirstElement();
if (el instanceof IFile) return (IFile)el;
}
return null;
}
}