package com.openMap1.mapper.actions; import java.util.Hashtable; import java.util.Iterator; import java.util.StringTokenizer; import java.util.Vector; 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.emf.ecore.EcorePackage; import org.eclipse.jface.action.IAction; import org.eclipse.ui.IObjectActionDelegate; import com.openMap1.mapper.AssocEndMapping; import com.openMap1.mapper.AssocMapping; import com.openMap1.mapper.AttributeDef; import com.openMap1.mapper.ElementDef; import com.openMap1.mapper.MappedStructure; import com.openMap1.mapper.MapperFactory; import com.openMap1.mapper.NodeMappingSet; import com.openMap1.mapper.ObjMapping; import com.openMap1.mapper.PropMapping; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.structures.MappableAssociation; import com.openMap1.mapper.structures.StructureDefinition; import com.openMap1.mapper.util.ModelUtil; import com.openMap1.mapper.views.WorkBenchUtil; public class MakeClassModelFromStructure extends MapperActionDelegate implements IObjectActionDelegate { private EPackage topPackage; private EPackage mainPackage; private Hashtable<String,EClass> allClasses; private StructureDefinition structureDef; private MappedStructure mappedStructure; public void run(IAction action) { try { mappedStructure = mappedStructure(); structureDef = mappedStructure.getStructureDefinition(); if (structureDef == null) throw new MapperException("There is no structure definition to expand"); String modelLocation = makeInitialModel(); allClasses = new Hashtable<String,EClass>(); ElementDef rootNode = mappedStructure.getRootElement(); rootNode.setExpanded(true); ElementDef newRoot = rootNode; // automatic expansion of all nodes can make the mapping set too big newRoot = expandAllNodes(rootNode); descendStructureTree(null,null,newRoot); mappedStructure.setRootElement(newRoot); // save the results ModelUtil.savePackage(modelLocation, topPackage); mappedStructure.setUMLModelURL(modelLocation); ModelUtil.saveMappingSet(mappedStructure.eResource()); } catch (Exception ex) { WorkBenchUtil.showMessage("Error",ex.getMessage()); ex.printStackTrace(); } } /** * expand all nodes in the tree structure * @param node * @return the node expanded, with all its descendants expanded * @throws MapperException */ private ElementDef expandAllNodes(ElementDef node) throws MapperException { //FIXME - deal with recursive nesting of nodes. if (!node.isExpanded()) { ElementDef newNode = structureDef.typeStructure(node.getType()); if (newNode == null) throw new MapperException("No structure for node " + node.getName() + " of type " + node.getType()); // two-stage replacement to avoid concurrent modification exception Vector<ElementDef> newChildren = new Vector<ElementDef>(); for (Iterator<ElementDef> it = newNode.getChildElements().iterator();it.hasNext();) { ElementDef child = it.next(); newChildren.add(expandAllNodes(child)); } for (Iterator<ElementDef> it = newChildren.iterator();it.hasNext();) node.getChildElements().add(it.next()); for (Iterator<AttributeDef> it = newNode.getAttributeDefs().iterator();it.hasNext();) { AttributeDef att = it.next(); node.getAttributeDefs().add(att); } node.setExpanded(true); } else if (node.isExpanded()) { for (Iterator<ElementDef> it = node.getChildElements().iterator();it.hasNext();) { ElementDef child = it.next(); expandAllNodes(child); } } return node; } /** * recursive descent of the mapped structure tree, making EClasses, * EReferences and EAttributes as appropriate * * @param ParentClass class represented by the parent node of this node * @param node current node in the tree */ private void descendStructureTree(EClass parentClass, String parentSubset, ElementDef node) throws MapperException { // add a node mapping set NodeMappingSet nodeMaps = MapperFactory.eINSTANCE.createNodeMappingSet(); node.setNodeMappingSet(nodeMaps); /* if this node has child nodes, make a class and an association * from class represented by the parent node; and descend */ if (node.getChildElements().size() > 0) { // make the class if it does not exist already String className = makeClassName(node.getName()); EClass aClass = allClasses.get(className); if (aClass == null) { aClass = EcoreFactory.eINSTANCE.createEClass(); aClass.setName(className); mainPackage.getEClassifiers().add(aClass); allClasses.put(className,aClass); // ensure the top class will be the root of the tree in the class model view if (parentClass == null) ModelUtil.addMIFAnnotation(aClass, "entry", "true"); } // make and add an object mapping ObjMapping om = MapperFactory.eINSTANCE.createObjMapping(); om.setMappedClass(className); om.setMappedPackage(aClass.getEPackage().getName()); String qualifiedClassName = ModelUtil.getQualifiedClassName(aClass); String subset = AddMapperEditorActions.nextSubset(mappedStructure, qualifiedClassName); om.setSubset(subset); nodeMaps.getObjectMappings().add(om); // make the association from the parent class, if it exists if (parentClass != null) { String refName = className.toLowerCase(); EReference newRef = EcoreFactory.eINSTANCE.createEReference(); newRef.setName(refName); newRef.setContainment(true); newRef.setEType(aClass); newRef.setLowerBound(node.getMinMultiplicity().getValue()); newRef.setUpperBound(node.getMaxMultiplicity().getValue()); parentClass.getEStructuralFeatures().add(newRef); // add an association mapping MappableAssociation mass = new MappableAssociation(parentClass,parentSubset, aClass,subset,newRef,true); AssocMapping am = MapperFactory.eINSTANCE.createAssocMapping(); for (int end = 1; end < 3; end ++) { AssocEndMapping aem = MapperFactory.eINSTANCE.createAssocEndMapping(); aem.setMappedRole(mass.roleName(end)); aem.setMappedClass(mass.endClass(end).getName()); aem.setMappedPackage(mass.endClass(end).getEPackage().getName()); aem.setSubset(mass.getSubset(end)); aem.setRequiredForObject(mass.requiredForEnd(end)); if (end == 1) am.setMappedEnd1(aem); if (end == 2) am.setMappedEnd2(aem); } nodeMaps.getAssociationMappings().add(am); } // recursive descent for (Iterator<ElementDef> it = node.getChildElements().iterator(); it.hasNext();) { ElementDef child = it.next(); descendStructureTree(aClass,subset,child); } } /* if this node has no child nodes, make it an EAttribute of the class * represented by the parent node; warn if it has multiplicity > 1 */ else if (node.getChildElements().size() == 0) { if (parentClass == null) throw new MapperException("Cannot make a class model with only one node"); String attName = makeClassName(node.getName()).toLowerCase(); EAttribute theAtt = EcoreFactory.eINSTANCE.createEAttribute(); theAtt.setName(attName); theAtt.setEType(EcorePackage.eINSTANCE.getEString()); theAtt.setLowerBound(node.getMinMultiplicity().getValue()); parentClass.getEStructuralFeatures().add(theAtt); // create and add the property mapping PropMapping pm = MapperFactory.eINSTANCE.createPropMapping(); pm.setMappedClass(parentClass.getName()); pm.setMappedPackage(parentClass.getEPackage().getName()); pm.setMappedProperty(attName); pm.setSubset(parentSubset); nodeMaps.getPropertyMappings().add(pm); } } private String makeClassName(String nodeName) { String className = ""; StringTokenizer st = new StringTokenizer(nodeName,"."); while (st.hasMoreTokens()) { className = className + st.nextToken(); if (st.hasMoreTokens()) className = className + "_"; } return className; } private String makeInitialModel() throws MapperException { // make an empty simplified Ecore model topPackage = EcoreFactory.eINSTANCE.createEPackage(); topPackage.setName("top"); // ensure this class model will be viewed tree-like, as if it were an RMIM in the class model view ModelUtil.addMIFAnnotation(topPackage, "RMIM", "true"); // add the main package which all the classes will be in mainPackage = EcoreFactory.eINSTANCE.createEPackage(); mainPackage.setName("main"); ModelUtil.addMIFAnnotation(mainPackage, "name", "main"); topPackage.getESubpackages().add(mainPackage); // save the empty Ecore model String mappingSetLocation = mappedStructure.eResource().getURI().toString(); StringTokenizer st = new StringTokenizer(mappingSetLocation,"."); // FIXME - should really put the class model in the ClassModel folder of the project String modelLocation = st.nextToken() + ".ecore"; ModelUtil.savePackage(modelLocation, topPackage); return modelLocation; } }