package controller.comparer.xmi; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.json.simple.JSONObject; import controller.compare.ComparerIntf; import controller.comparer.xmi.request.Request; import controller.merge.xmi.xclass.XmiMergedAssociation; import controller.merge.xmi.xclass.XmiMergedClass; import controller.upload.FileInfo; import controller.upload.UploadProcessorFactory; import controller.util.FileUtil; public class XmiClassDiagramComparer implements ComparerIntf { private final static String REQUEST_PACKAGE = "controller.comparer.xmi.request"; private final static String KEY_REQUEST = "Request"; // These request will be removed in final version private final static String REQUEST_REFRESH = "Refresh"; private final static String REQUEST_CONSOLIDATE = "Consolidate"; private final static String REQUEST_ADD = "Add"; private final static String REQUEST_BREAK = "Break"; private final static String REQUEST_COMPARE = "Compare"; // Parser elements that contain the metamodel private XmiClassDiagramParser ClassDiagram1; private XmiClassDiagramParser ClassDiagram2; // Store merged classes private ArrayList<XmiMergedClass> sameClass = new ArrayList<XmiMergedClass>(); // Classes unique to diagram 1 private ArrayList<XmiClassElement> uniqueClass1 = new ArrayList<XmiClassElement>(); // Classes unique to diagram 2 private ArrayList<XmiClassElement> uniqueClass2 = new ArrayList<XmiClassElement>(); // Associations used by merge process to generate association elements private ArrayList<XmiMergedAssociation> associationUml = new ArrayList<XmiMergedAssociation>(); /** * Constructor * * @param XmiFiles1 * @param XmiFiles2 */ public XmiClassDiagramComparer(List<FileInfo> XmiFiles1, List<FileInfo> XmiFiles2) { // Process the first file FileInfo classDiagram1Notation = FileUtil.getFile( UploadProcessorFactory.NOTATION_EXTENSION, XmiFiles1); FileInfo classDiagram1Uml = FileUtil.getFile( UploadProcessorFactory.UML_EXTENSION, XmiFiles1); ClassDiagram1 = new XmiClassDiagramParser( classDiagram1Uml.getDestFilePath() + classDiagram1Uml.getFileName(), classDiagram1Notation.getDestFilePath() + classDiagram1Notation.getFileName()); // Process the second file FileInfo classDiagram2Notation = FileUtil.getFile( UploadProcessorFactory.NOTATION_EXTENSION, XmiFiles2); FileInfo classDiagram2Uml = FileUtil.getFile( UploadProcessorFactory.UML_EXTENSION, XmiFiles2); ClassDiagram2 = new XmiClassDiagramParser( classDiagram2Uml.getDestFilePath() + classDiagram2Uml.getFileName(), classDiagram2Notation.getDestFilePath() + classDiagram2Notation.getFileName()); GenerateClassLists(); } /** * Based on the JSON object's request, this method invokes the desired * request and returns a JSON object. * * JSON structure is documented in the JSON documentation. */ @SuppressWarnings("unchecked") @Override public JSONObject action(JSONObject jsonObj) { String request = REQUEST_PACKAGE + "." + (String) jsonObj.get(KEY_REQUEST); // controller.comparer.xmi.request. ... // Create request object via Reflection Request requestObj; try { requestObj = (Request) Class.forName(request).newInstance(); return requestObj.request(jsonObj, this); } catch (Exception e) { JSONObject failResponse = new JSONObject(); failResponse.put("Response", "Fail"); failResponse.put("Message", e.getMessage()); e.printStackTrace(); return failResponse; } } // ************************************************************************* // Unofficial stubs below - Decoupling Request objects and // XmiClassDiagramComparer // ************************************************************************* /** * Based on the JSON object's request, this method invokes the desired * request and returns a JSON object. * * JSON structure is documented in the JSON documentation. */ public JSONObject actionTest(JSONObject jsonObj) { String request = (String) jsonObj.get(KEY_REQUEST); switch (request) { case REQUEST_REFRESH: return Refresh(jsonObj); case REQUEST_COMPARE: return Compare(jsonObj); case REQUEST_CONSOLIDATE: return Consolidate(jsonObj); case REQUEST_ADD: return Add(jsonObj); case REQUEST_BREAK: return Break(jsonObj); } JSONObject jObj = new JSONObject(); jObj.put("Response", "Fail"); return jObj; } @SuppressWarnings("unchecked") private JSONObject Refresh(JSONObject jsonObj) { JSONObject jObj = new JSONObject(); ArrayList<String> class1 = new ArrayList<String>(); class1.add("Vehicle"); ArrayList<String> class2 = new ArrayList<String>(); class2.add("Vehicle"); class2.add("Bus"); ArrayList<String> same = new ArrayList<String>(); same.add("Car"); same.add("Bike"); jObj.put("Class1", class1); jObj.put("Class2", class2); jObj.put("Same", same); jObj.put("Response", "Success"); return jObj; } private JSONObject Compare(JSONObject jsonObj) { JSONObject jObj = new JSONObject(); jObj.put("Class1", "Vehicle"); jObj.put("Class2", "Vehicle"); ArrayList<String> arraylist = new ArrayList<String>(); HashMap<String, ArrayList<String>> attr = new HashMap<String, ArrayList<String>>(); arraylist.add("<Undefined> Color"); attr.put("Class2", arraylist); arraylist = new ArrayList<String>(); HashMap<String, ArrayList<String>> op = new HashMap<String, ArrayList<String>>(); arraylist.add("Start()"); op.put("Class1", arraylist); arraylist = new ArrayList<String>(); arraylist.add("Stop()"); op.put("Class2", arraylist); jObj.put("Attributes", attr); jObj.put("Operations", op); jObj.put("Response", "Success"); return jObj; } private JSONObject Consolidate(JSONObject jsonObj) { JSONObject jObj = new JSONObject(); jObj.put("Response", "Success"); return jObj; } private JSONObject Add(JSONObject jsonObj) { JSONObject jObj = new JSONObject(); jObj.put("Class2", "Bus"); ArrayList<String> arraylist = new ArrayList<String>(); arraylist.add("<Undefined> Benches"); jObj.put("Attributes", arraylist); arraylist = new ArrayList<String>(); arraylist.add("StopSign()"); jObj.put("Operations", arraylist); jObj.put("Response", "Success"); return jObj; } private JSONObject Break(JSONObject jsonObj) { JSONObject jObj = new JSONObject(); jObj.put("Response", "Success"); return jObj; } // ********** END TEST STUBS ********************************** /** * @return the sameClass */ public ArrayList<XmiMergedClass> getSameClass() { return sameClass; } /** * @param sameClass * the sameClass to set */ public void setSameClass(ArrayList<XmiMergedClass> sameClass) { this.sameClass = sameClass; } /** * @return the uniqueClass1 */ public ArrayList<XmiClassElement> getUniqueClass1() { return uniqueClass1; } /** * @param uniqueClass1 * the uniqueClass1 to set */ public void setUniqueClass1(ArrayList<XmiClassElement> uniqueClass1) { this.uniqueClass1 = uniqueClass1; } /** * @return the uniqueClass2 */ public ArrayList<XmiClassElement> getUniqueClass2() { return uniqueClass2; } /** * @param uniqueClass2 * the uniqueClass2 to set */ public void setUniqueClass2(ArrayList<XmiClassElement> uniqueClass2) { this.uniqueClass2 = uniqueClass2; } /** * @return the classDiagram1 */ public final XmiClassDiagramParser getClassDiagram1() { return ClassDiagram1; } /** * @return the classDiagram2 */ public final XmiClassDiagramParser getClassDiagram2() { return ClassDiagram2; } /** * Create the list of unique and same class lists. */ private void GenerateClassLists() { // Keep track of class elements to remove (avoid concurrency issues) ArrayList<XmiClassElement> trackRemoveClass1 = new ArrayList<XmiClassElement>(); ArrayList<XmiClassElement> trackRemoveClass2 = new ArrayList<XmiClassElement>(); // populate unique elements then search for classes that are perfectly // the same for (XmiClassElement class1 : ClassDiagram1.getClassElements()) { uniqueClass1.add(class1); } for (XmiClassElement class2 : ClassDiagram2.getClassElements()) { uniqueClass2.add(class2); } for (XmiClassElement class1 : uniqueClass1) { for (XmiClassElement class2 : uniqueClass2) { if (class1.equals(class2)) { trackRemoveClass1.add(class1); trackRemoveClass2.add(class2); sameClass.add(new XmiMergedClass(class1, class2)); } } } // remove not unique classes for (XmiClassElement class1 : trackRemoveClass1) { uniqueClass1.remove(class1); } for (XmiClassElement class2 : trackRemoveClass2) { uniqueClass2.remove(class2); } } /** * Used for testing to see the information stored */ public static void TestPrintOutput(String fileName, ArrayList<XmiMergedClass> mergedList) { // TESTing shows all elements System.out.println("Diagram: " + fileName); for (XmiMergedClass mergedClass : mergedList) { if (mergedClass.getClass1() != null) { System.out.println("Class " + mergedClass.getClass1().toString()); } if (mergedClass.getAttributes() != null) { for (XmiAttributeElement element : mergedClass.getAttributes()) { System.out.println("Attribute1 " + element.toString()); } } if (mergedClass.getAttributes2() != null) { for (XmiAttributeElement element : mergedClass.getAttributes2()) { System.out.println("Attribute2 " + element.toString()); } } if (mergedClass.getOperations() != null) { for (XmiOperationElement element : mergedClass.getOperations()) { System.out.println("Operation1 " + element.toString()); } } if (mergedClass.getOperations2() != null) { for (XmiOperationElement element : mergedClass.getOperations2()) { System.out.println("Operation2 " + element.toString()); } } if (mergedClass.getGeneralizations() != null) { for (XmiGeneralizationElement element : mergedClass.getGeneralizations()) { System.out.println("Generalization1 " + element.toString()); } } if (mergedClass.getGeneralizations2() != null) { for (XmiGeneralizationElement element : mergedClass.getGeneralizations2()) { System.out.println("Generalization2 " + element.toString()); } } if (mergedClass.getAssociations() != null) { for (XmiAssociationElement element : mergedClass.getAssociations()) { System.out.println("Association " + element.toString()); } } if (mergedClass.getAssociations2() != null) { for (XmiAssociationElement element : mergedClass.getAssociations2()) { System.out.println("Association2 " + element.toString()); } } } } /** * @return the associationUml */ public ArrayList<XmiMergedAssociation> getAssociationUml() { return associationUml; } /** * @param associationUml the associationUml to set */ public void setAssociationUml(ArrayList<XmiMergedAssociation> associationUml) { this.associationUml = associationUml; } }