package controller.comparer.xmi;
/**
* Look into refactoring this and UploadXmiParser because both use the same code to find the active elements in uml file
*
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import uml2parser.Attribute;
import uml2parser.ModelFileInfo;
import uml2parser.ParseXmi;
import uml2parser.XmiElement;
public class XmiClassDiagramParser {
// Class diagram signifier
private final static String PAPYRUS_CLASS_DIAG = "PapyrusUMLClassDiagram";
// Tags
private final static String PAPYRUS_HEADER_ELEM = "uml:Model";
private final static String PAPYRUS_NOTATION_ELEM = "notation:Diagram";
private final static String PAPYRUS_PACKAGED_ELEM = "packagedElement";
private final static String PAPYRUS_OPERATION_ELEM = "ownedOperation";
private final static String PAPYRUS_PROPERTY_ELEM = "ownedAttribute";
private final static String PAPYRUS_PARAMETER_ELEM = "ownedParameter";
private final static String PAPYRUS_GENERALIZATION_ELEM = "generalization";
private final static String PAPYRUS_MEMVBER_END = "ownedEnd";
private final static String PAPYRUS_LOWER_VALUE = "lowerValue";
private final static String PAPYRUS_UPPER_VALUE = "upperValue";
private final static String PAPYRUS_DEFAULT_VALUE = "defaultValue";
// UML Types
private final static String PAPYRUS_PACKAGE_TYPE_CLASS = "uml:Class";
private final static String PAPYRUS_PACKAGE_TYPE_INTERFACE = "uml:Interface";
private final static String PAPYRUS_PACKAGE_TYPE_PRIMITIVE = "uml:PrimitiveType";
private final static String PAPYRUS_PACKAGE_TYPE_ASSOCIATION = "uml:Association";
private final static String PAPYRUS_PACKAGE_TYPE_LITERNAL_INTEGER = "uml:LiteralInteger";
private final static String PAPYRUS_PACKAGE_TYPE_LITERNAL_UNLILMITED = "uml:LiteralUnlimitedNatural";
// Attributes
private final static String PAPYRUS_XMI_ATTRIBUTE_TYPE = "xmi:type";
private final static String PAPYRUS_ATTRIBUTE_NAME = "name";
private final static String PAPYRUS_ATTRIBUTE_ID = "xmi:id";
private final static String PAPYRUS_ATTRIBUTE_TYPE = "type";
private final static String PAPYRUS_ATTRIBUTE_VISIBILITY = "visibility";
private final static String PAPYRUS_ATTRIBUTE_DIRECTION = "direction";
private final static String PAPYRUS_GENERALIZATION_DIRECTION = "general";
private final static String PAPYRUS_ATTRIBUTE_ASSOCIATION = "association";
private final static String PAPYRUS_ATTRIBUTE_VALUE = "value";
private final static String PAPYRUS_MEMBER_END = "memberEnd";
private final static String PAPYRUS_AGGREGATION = "aggregation";
private final static String PAPYRUS_NAVIGABLE = "navigableOwnedEnd";
private String umlFileName;
private String notationFileName;
// Stores the header tag for uml:Model's name and id
private String umlModelName;
private String umlModelId;
private ModelFileInfo modelUmlInfo;
private ModelFileInfo notationmodelInfo;
private boolean isClassDiag = false;
// Check for active items in notation that will be found in uml file
private List<String> activeIdList;
private XmiElement classXmiDiag;
// Store elements used by compare algorithm
private Stack<XmiElement> stack = new Stack<XmiElement>();
private ArrayList<XmiBaseElement> rootElements = new ArrayList<XmiBaseElement>();
private ArrayList<XmiClassElement> classElements = new ArrayList<XmiClassElement>();
private ArrayList<XmiTypeElement> primitiveElements = new ArrayList<XmiTypeElement>();
private ArrayList<XmiAssociationElement> associationElements = new ArrayList<XmiAssociationElement>();
private ArrayList<XmiGeneralizationElement> generalizationElements = new ArrayList<XmiGeneralizationElement>();
public XmiClassDiagramParser(String umlFile, String notationFile) {
umlFileName = umlFile;
notationFileName = notationFile;
activeIdList = new ArrayList<String>();
this.process();
this.postProcess();
TestPrintOutput();
}
/**
* Used for testing to see the information stored for this parser
*/
public void TestPrintOutput() {
// TESTing shows all elements
System.out.println("Diagram: " + umlFileName);
for (XmiBaseElement Class : rootElements) {
if (Class instanceof XmiClassElement) {
System.out.println("Class " + Class.toString());
for (XmiAttributeElement element : ((XmiClassElement) Class)
.getAttributes()) {
System.out.println("Attribute " + element.toString());
}
for (XmiOperationElement element : ((XmiClassElement) Class)
.getOperations()) {
System.out.println("Operation " + element.toString());
}
for (XmiClassElement element : ((XmiClassElement) Class)
.getNestedClass()) {
System.out.println("Nested: " + element.toString());
}
for (XmiGeneralizationElement element : ((XmiClassElement) Class)
.getGeneralization()) {
System.out.println("Generalization " + element.toString());
}
} else if (Class instanceof XmiTypeElement) {
System.out.println("Primitive " + Class.toString());
}
}
for (XmiAssociationElement association : associationElements) {
System.out.println("Association " + association.toString());
for (XmiMemberEndElement memberEnd : association.getMemberEnds()) {
System.out.println("Member End " + memberEnd.toString());
}
}
}
// Process is the same as the Upload Xmi functionality (Refactor code)
private void process() {
// Parse the UML File
// first process the .notation file
notationmodelInfo = new ModelFileInfo(notationFileName);
ParseXmi notationXmi = new ParseXmi(notationmodelInfo);
notationXmi.parseDoc();
// second process the .uml file
modelUmlInfo = new ModelFileInfo(umlFileName);
ParseXmi umlXmi = new ParseXmi(modelUmlInfo);
umlXmi.parseDoc();
// Does the diagram support Class diagrams & sequence diagrams
List<XmiElement> elemList = notationmodelInfo
.findElementsByName(PAPYRUS_NOTATION_ELEM);
if (elemList.size() > 0) {
for (int i = 0; i < elemList.size(); i++) {
XmiElement xmi = elemList.get(i);
List<Attribute> attriblist = xmi.getAttrib();
for (int j = 0; j < attriblist.size(); j++) {
Attribute attr = attriblist.get(j);
if (attr.getName().equals("type")) {
switch (attr.getValue()) {
case PAPYRUS_CLASS_DIAG: {
// TODO: We are currently only supporting one class
// diagram per
// Notation file. We can enhance this in future.
classXmiDiag = xmi;
isClassDiag = true;
}
break;
default: {
break;
}
}
}
}
}
}
// need to find the active elements in the class diagram
if (isClassDiag) {
ActiveElementIterator(classXmiDiag);
// Check for error
boolean foundError = false;
// now find the elements in the class
for (int i = 0; i < activeIdList.size(); i++) {
if (modelUmlInfo.findElementsById(activeIdList.get(i)) == false) {
foundError = true;
break;
}
}
if (!foundError) {
// Build a list of Class.
BuildXmiCompareElementStructure(modelUmlInfo);
}
}
}
/**
* postProcess
*
*/
private void postProcess() {
DefineReferenceTypeName();
DefineGeneralizationParent();
}
/**
*
* @param ElemName
* @return
*/
public List<XmiElement> findElementsByName(String TargetName,
XmiElement xmiParent) {
List<XmiElement> elementList = new ArrayList<XmiElement>();
ElementIterator(xmiParent, TargetName, elementList);
return elementList;
}
/**
*
* @param name
* @param elemname
* @param elementList
*/
private void ElementIterator(XmiElement name, String elemname,
List<XmiElement> elementList) {
List<XmiElement> childElementlist = name.getChildElemList();
// Log.LogCreate().Info("ElementIterator: Element name " +
// name.getElementName());
if (name.getElementName().equals(elemname)) {
elementList.add(name);
}
if (childElementlist != null) {
for (int i = 0; i < childElementlist.size(); i++) {
ElementIterator(childElementlist.get(i), elemname, elementList);
}
}
return;
}
/**
* Sets the active flag for elements found in notation and uml files
*
* @param element
*/
private void ActiveElementIterator(XmiElement element) {
List<XmiElement> childElementlist = element.getChildElemList();
if (childElementlist != null) {
// iterate the xmiElement which contains all the information
for (int i = 0; i < childElementlist.size(); i++) {
ActiveElementIterator(childElementlist.get(i));
}
}
List<Attribute> attribList = element.getAttrib();
for (int j = 0; j < attribList.size(); j++) {
Attribute attrib = attribList.get(j);
if (attrib.getName().equals("href")) {
int beginIndex = attrib.getValue().indexOf('#');
String value = attrib.getValue().substring(beginIndex + 1);
// Log.LogCreate().Info("Active IDs " + value);
activeIdList.add(value);
}
}
}
/**
* DefineReferenceTypeName
*
* Runs through elements and finds the names for the types if they are
* reference. A type that is a reference begings with an underscore.
*/
private void DefineReferenceTypeName() {
for (XmiClassElement Class : classElements) {
for (XmiAttributeElement element : Class.getAttributes()) {
if (element.getUmlType().startsWith("_")) {
element.setTypeName(Utility.getBaseNameById(rootElements,
element.getUmlType()));
}
}
for (XmiOperationElement element : Class.getOperations()) {
if (element.getUmlType().startsWith("_")) {
element.setTypeName(Utility.getBaseNameById(rootElements,
element.getUmlType()));
}
}
for (XmiClassElement element : Class.getNestedClass()) {
if (element.getUmlType().startsWith("_")) {
element.setTypeName(Utility.getBaseNameById(rootElements,
element.getUmlType()));
}
}
for (XmiGeneralizationElement element : Class.getGeneralization()) {
if (element.getUmlType().startsWith("_")) {
element.setTypeName(Utility.getBaseNameById(rootElements,
element.getUmlType()));
}
}
}
}
/**
* DefineGeneralizationParent
*
* Runs through genearlization elements and defines the parent element. Must
* be done during post processing to make sure parent (XmiClassElement)
* exists.
*/
private void DefineGeneralizationParent() {
for (XmiClassElement Class : classElements) {
for (XmiGeneralizationElement element : Class.getGeneralization()) {
if (element.getParent() == null) {
element.setParentElement(Utility.getClassById(
this.classElements, element.getParent()));
}
}
}
}
/**
* Builds a list of Class XmiElements which will be used by the compare
* algorithm.
*/
private void BuildXmiCompareElementStructure(ModelFileInfo modelUmlInfo) {
// Obtain name and id of uml diagram
List<XmiElement> headerList = modelUmlInfo
.findElementsByName(PAPYRUS_HEADER_ELEM);
if (!headerList.isEmpty()) {
// Only 1 element in the headerList
XmiElement header = headerList.get(0);
this.umlModelName = header
.getAttributeValue(PAPYRUS_ATTRIBUTE_NAME);
this.umlModelId = header.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
}
// Iterate through all packagedElemets to construct Class model
List<XmiElement> packagedElemList = modelUmlInfo
.findElementsByName(PAPYRUS_PACKAGED_ELEM);
for (int i = 0; i < packagedElemList.size(); i++) {
if (packagedElemList.get(i).getFoundMatch()) {
// classFlag = false;
List<Attribute> attrlist = packagedElemList.get(i).getAttrib();
for (int j = 0; j < attrlist.size(); j++) {
if (isClassLevel(attrlist.get(j))) {
String tag = attrlist.get(j).getValue();
switch (tag) {
case PAPYRUS_PACKAGE_TYPE_PRIMITIVE: {
XmiTypeElement typeElement = createXmiTypeElement(packagedElemList
.get(i));
rootElements.add(typeElement);
primitiveElements.add(typeElement);
break;
}
case PAPYRUS_PACKAGE_TYPE_CLASS: {
XmiClassElement classElement = createXmiClassElement(packagedElemList
.get(i));
rootElements.add(classElement);
classElements.add(classElement);
break;
}
case PAPYRUS_PACKAGE_TYPE_INTERFACE: {
XmiClassElement classElement = createXmiClassElement(packagedElemList
.get(i));
rootElements.add(classElement);
classElements.add(classElement);
break;
}
case PAPYRUS_PACKAGE_TYPE_ASSOCIATION: {
XmiAssociationElement assocationElement = createXmiAssociationElement(packagedElemList
.get(i));
rootElements.add(assocationElement);
associationElements.add(assocationElement);
break;
}
}
}
}
/*
* if (classFlag) { List<XmiElement> target =
* findElementsByName( PAPYRUS_ATTRIBUTE_ELEM, stack.peek());
* for (XmiElement element : target) {
*
* System.out.println("Attribute: " +
* element.getAttributeValue("name")); } }
*/
}
}
}
private XmiTypeElement createXmiTypeElement(XmiElement xmiElement) {
String type = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_TYPE);
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String name = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_NAME);
return new XmiTypeElement(id, name, type, "");
}
private XmiClassElement createXmiClassElement(XmiElement xmiElement) {
List<XmiElement> childElements = xmiElement.getChildElemList();
String type = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_TYPE);
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String name = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_NAME);
XmiClassElement xmiClass = new XmiClassElement(id, name, type, "");
for (int j = 0; j < childElements.size(); j++) {
if (!childElements.get(j).getFoundMatch()) {
continue;
}
String tag = childElements.get(j).getElementName();
String association = childElements.get(j).getAttributeValue(
PAPYRUS_ATTRIBUTE_ASSOCIATION);
switch (tag) {
case PAPYRUS_PROPERTY_ELEM:
if (association == null) {
xmiClass.addAttribute(createXmiAttributeElement(childElements
.get(j)));
} else {
xmiClass.addClassifer(createXmiMemberEndElement(childElements
.get(j)));
}
break;
case PAPYRUS_OPERATION_ELEM:
xmiClass.addOperation(createXmiOperationElement(childElements
.get(j)));
break;
case PAPYRUS_GENERALIZATION_ELEM:
xmiClass.addGeneralization(createXmiGeneralizationElement(childElements
.get(j)));
break;
}
}
return xmiClass;
}
/**
* Checks if the attribute is for a valid Class level element (Class,
* Interface, etc)
*
* @param attribute
* @return true if valid, else false
*/
public boolean isClassLevel(Attribute attribute) {
String name = attribute.getName();
String value = attribute.getValue();
if (name.equals(PAPYRUS_XMI_ATTRIBUTE_TYPE)
&& (value.equals(PAPYRUS_PACKAGE_TYPE_ASSOCIATION)
|| value.equals(PAPYRUS_PACKAGE_TYPE_CLASS)
|| value.equals(PAPYRUS_PACKAGE_TYPE_INTERFACE) || value
.equals(PAPYRUS_PACKAGE_TYPE_PRIMITIVE))) {
return true;
}
return false;
}
private XmiAttributeElement createXmiAttributeElement(XmiElement xmiElement) {
String type = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_TYPE);
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String name = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_NAME);
String visibility = xmiElement
.getAttributeValue(PAPYRUS_ATTRIBUTE_VISIBILITY);
XmiAttributeElement xmiAttribute = new XmiAttributeElement(id, name,
type, visibility);
List<XmiElement> childrenElement = xmiElement.getChildElemList();
for (XmiElement child : childrenElement) {
String tag = child.getElementName();
switch (tag) {
case PAPYRUS_LOWER_VALUE:
xmiAttribute.setLowerValue(createXmiValueElement(child));
break;
case PAPYRUS_UPPER_VALUE:
xmiAttribute.setUpperValue(createXmiValueElement(child));
break;
case PAPYRUS_DEFAULT_VALUE:
xmiAttribute
.setDefaultValue(createXmiDefaultValueElement(child));
break;
}
}
return xmiAttribute;
}
private XmiOperationElement createXmiOperationElement(XmiElement xmiElement) {
String type = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_TYPE);
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String name = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_NAME);
String visibility = xmiElement
.getAttributeValue(PAPYRUS_ATTRIBUTE_VISIBILITY);
XmiOperationElement xmiOperation = new XmiOperationElement(id, name, type,
visibility);
List<XmiElement> childrenElement = xmiElement.getChildElemList();
for (XmiElement child : childrenElement) {
String tag = child.getElementName();
switch (tag) {
case PAPYRUS_PARAMETER_ELEM:
xmiOperation.addParameter(createXmiParameterElement(child));
break;
}
}
return xmiOperation;
}
private XmiParameterElement createXmiParameterElement(XmiElement xmiElement) {
String type = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_TYPE);
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String name = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_NAME);
String visibility = xmiElement
.getAttributeValue(PAPYRUS_ATTRIBUTE_VISIBILITY);
String direction = xmiElement
.getAttributeValue(PAPYRUS_ATTRIBUTE_DIRECTION);
return new XmiParameterElement(id, name, type, visibility, direction);
}
private XmiGeneralizationElement createXmiGeneralizationElement(
XmiElement xmiElement) {
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String generalization = xmiElement
.getAttributeValue(PAPYRUS_GENERALIZATION_DIRECTION);
XmiGeneralizationElement gen = new XmiGeneralizationElement(id, generalization);
// Populate a list of generalizations
generalizationElements.add(gen);
return gen;
}
private XmiAssociationElement createXmiAssociationElement(
XmiElement xmiElement) {
String type = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_TYPE);
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String name = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_NAME);
XmiAssociationElement xmiAssociation = new XmiAssociationElement(id,
name, type);
String navigable = xmiElement.getAttributeValue(PAPYRUS_NAVIGABLE);
if (navigable != null) {
xmiAssociation.setNavigable(navigable);
}
List<XmiElement> childrenElement = xmiElement.getChildElemList();
for (XmiElement child : childrenElement) {
String tag = child.getElementName();
switch (tag) {
case PAPYRUS_MEMVBER_END:
XmiMemberEndElement memberEndChild = createXmiMemberEndElement(child);
xmiAssociation.addMemberEnd(memberEndChild);
memberEndChild.setAssociation(xmiAssociation);
break;
}
}
return xmiAssociation;
}
private XmiMemberEndElement createXmiMemberEndElement(XmiElement xmiElement) {
String type = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_TYPE);
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String name = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_NAME);
String aggregationValue = xmiElement
.getAttributeValue(PAPYRUS_AGGREGATION);
String associationId = xmiElement
.getAttributeValue(PAPYRUS_ATTRIBUTE_ASSOCIATION);
XmiMemberEndElement xmiClass = new XmiMemberEndElement(id, name, type);
if (aggregationValue != null) {
xmiClass.setAggregation(AggregationValues.valueOf(aggregationValue.toUpperCase()));
}
xmiClass.setAssociationId(associationId);
List<XmiElement> childrenElement = xmiElement.getChildElemList();
for (XmiElement child : childrenElement) {
String tag = child.getElementName();
switch (tag) {
case PAPYRUS_LOWER_VALUE:
xmiClass.setLowerValue(createXmiValueElement(child));
break;
case PAPYRUS_UPPER_VALUE:
xmiClass.setUpperValue(createXmiValueElement(child));
break;
}
}
return xmiClass;
}
private XmiValueElement createXmiValueElement(XmiElement xmiElement) {
String type = xmiElement.getAttributeValue(PAPYRUS_XMI_ATTRIBUTE_TYPE);
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String value = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_VALUE);
return new XmiValueElement(id, type, value);
}
private XmiValueElement createXmiDefaultValueElement(XmiElement xmiElement) {
String type = xmiElement.getAttributeValue(PAPYRUS_XMI_ATTRIBUTE_TYPE);
String id = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_ID);
String name = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_NAME);
String value = xmiElement.getAttributeValue(PAPYRUS_ATTRIBUTE_VALUE);
if (value == null) {
return new XmiValueElement(id, type, true);
} else if (value.isEmpty()) {
return new XmiValueElement(id, type, true);
} else {
return new XmiValueElement(id, name, type, value);
}
}
/**
* Returns the generic parsed information Notation file
*
* @return ModelFileInfo for the notation file
*/
public ModelFileInfo getNotationFile() {
return notationmodelInfo;
}
/**
* Returns the generic parsed information for the UML file
*
* @return ModelFileInfo for the uml file
*/
public ModelFileInfo getUmlFile() {
return modelUmlInfo;
}
/**
* Returns the list of Active Root elements
*
* @return List object of XmiElement
*/
public List<XmiBaseElement> getRootElements() {
return rootElements;
}
/**
* Returns the list of Active Class elements
*
* @return List object of XmiElement
*/
public List<XmiClassElement> getClassElements() {
return classElements;
}
/**
* Returns the list of Active association elements
*
* @return List object of XmiAssociationElement
*/
public List<XmiAssociationElement> getAssociationElements() {
return associationElements;
}
/**
* Returns the list of Active generalization elements
*
* @return List object of XmiAssociationElement
*/
public List<XmiGeneralizationElement> getGeneralizationElements() {
return generalizationElements;
}
/**
* Returns the list of Active Type elements
*
* @return List object of XmiElement
*/
public List<XmiTypeElement> getTypeElements() {
return primitiveElements;
}
/**
* @return the umlModeName
*/
public String getUmlModeName() {
return umlModelName;
}
/**
* @param umlModeName
* the umlModeName to set
*/
public void setUmlModeName(String umlModeName) {
this.umlModelName = umlModeName;
}
/**
* @return the umlModelId
*/
public String getUmlModelId() {
return umlModelId;
}
/**
* @param umlModelId
* the umlModelId to set
*/
public void setUmlModelId(String umlModelId) {
this.umlModelId = umlModelId;
}
}