package controller.merge.xmi.xclass;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Queue;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import uml2parser.Attribute;
import uml2parser.ModelFileInfo;
import uml2parser.XmiElement;
public class XmiMergeClassNotationProcessor {
private final static String TAG_CHILDREN = "children";
private final static String TAG_EANNOTATIONS = "eAnnotations";
private final static String TAG_STYLES = "styles";
private final static String TAG_LAYOUT_CONSTRAINT = "layoutConstraint";
private final static String TAG_ELEMENT = "element";
private final static String TAG_EDGE = "edge";
private final static String ATTRIBUTE_TYPE = "type";
private final static String ATTRIBUTE_XMI_TYPE = "xmi:type";
private final static String ATTRIBUTE_XMI_ID = "xmi:id";
private final static String ATTRIBUTE_HREF = "href";
private final static String ATTRIBUTE_TARGET = "target";
private final static String ATTRIBUTE_SOURCE = "source";
private final static String TYPE_NOTATION_DECORATIONONDE = "notation:DecorationNode";
private final static String TYPE_NOTATION_BASICCOMPARTMENT = "notation:BasicCompartment";
// Type values for attribute, operation and nested class compartments in a class
private final static String TYPE_VALUE_ATTRIBUTE = "7017";
private final static String TYPE_VALUE_OPERATION = "7018";
private final static String TYPE_VALUE_NESTED_CLASS = "7019";
private String newFileName = "TEST";
private String umlFileId;
private String notationName;
private String notationId;
private HashMap<String, String> mapElementToChildren = new HashMap<String, String>();
private HashMap<String, String> mapClass2Ids = new HashMap<String, String>();
private HashMap<String, String> mapParentToSource = new HashMap<String, String>();
private Queue<XmiNotationElement> elements;
// fields for DOM
private DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance();
private DocumentBuilder docBuilder;
private Document umlDoc;
private Element umlRootElement;
public XmiMergeClassNotationProcessor(NotationData notationData) {
this(notationData.getElements(),
notationData.getReplaceClass2Id(),
notationData.getMapParentToSource(),
notationData.getFileName(),
notationData.getUmlId(),
notationData.getNotationName(),
notationData.getNotationId());
}
private XmiMergeClassNotationProcessor(Queue<XmiNotationElement> elements, HashMap<String, String> replaceClass2Id, HashMap<String, String> mapParentToSource, String fileName, String umlId, String notationName, String notationId) {
this.elements = elements;
this.umlFileId = umlId;
this.newFileName = fileName;
this.notationName = notationName;
this.notationId = notationId;
this.mapClass2Ids = replaceClass2Id;
this.mapParentToSource = mapParentToSource;
try {
Initialize();
while (!elements.isEmpty()) {
createNode(elements.poll(), umlDoc, umlRootElement);
}
umlRootElement.appendChild(createUmlElement(umlDoc));
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
private void Initialize() throws ParserConfigurationException {
docBuilder = docFactory.newDocumentBuilder();
// UML Header
umlDoc = docBuilder.newDocument();
umlRootElement = umlDoc.createElement("notation:Diagram");
umlRootElement.setAttribute("xmi:version", "2.0");
umlRootElement.setAttribute("xmlns:xmi",
"http://www.omg.org/XMI");
umlRootElement.setAttribute("xmlns:ecore",
"http://www.eclipse.org/emf/2002/Ecore");
umlRootElement.setAttribute("xmlns:notation",
"http://www.eclipse.org/gmf/runtime/1.0.2/notation");
umlRootElement.setAttribute("xmlns:uml",
"http://www.eclipse.org/uml2/4.0.0/UML");
umlRootElement.setAttribute("type",
"PapyrusUMLClassDiagram");
umlRootElement.setAttribute("measurementUnit",
"Pixel");
umlRootElement.setAttribute("name", this.newFileName);
umlRootElement.setAttribute("xmi:id", this.notationId);
umlDoc.appendChild(umlRootElement);
}
private Element createUmlElement(Document doc) {
Element umlElement = doc.createElement(TAG_ELEMENT);
umlElement.setAttribute(ATTRIBUTE_HREF, ClassMergeUtility.buildHref(umlFileId, newFileName));
umlElement.setAttribute(ATTRIBUTE_XMI_TYPE, "uml:Model");
return umlElement;
}
private void createNode(XmiNotationElement element, Document doc, Element rootElement) {
if (element.getType() == XmiNotationElement.TYPE_GENERALIZATION) {
createRelationNode(element, doc, rootElement);
}else if (element.getType() == XmiNotationElement.TYPE_ASSOCIATION) {
createAssociationNode(element, doc, rootElement);
} else {
createClassNode(element, doc, rootElement);
}
}
private void createClassNode(XmiNotationElement element, Document doc, Element rootElement) {
ModelFileInfo notation = element.getNotation();
String href = notation.getFileNameNoExtension() + ".uml#" + element.getId();
// Build class
XmiElement parentXmiElement = notation.getXmiElementFromHref(href).getParentElem();
Element parentElement = generateElement(parentXmiElement, doc);
// Store mapping information for target tag. Store the uml element ID to the notation children Id
mapElementToChildren.put(element.getId(), parentElement.getAttribute(ATTRIBUTE_XMI_ID));
for (XmiElement xmiElement : parentXmiElement.getChildElemList()) {
String tag = xmiElement.getElementName();
switch(tag) {
case TAG_CHILDREN:
parentElement.appendChild(generateChildren(xmiElement, doc, element));
break;
case TAG_ELEMENT:
Element elementTag = doc.createElement(TAG_ELEMENT);
for (Attribute attribute : xmiElement.getAttrib()) {
if (attribute.getName().equals(ATTRIBUTE_HREF)) {
elementTag.setAttribute(attribute.getName(), ClassMergeUtility.buildHref(element.getId(), this.newFileName));
} else {
elementTag.setAttribute(attribute.getName(), attribute.getValue());
}
}
parentElement.appendChild(elementTag);
break;
default:
parentElement.appendChild(generateElementAndChildren(xmiElement, doc));
}
}
rootElement.appendChild(parentElement);
}
// Generate children tag elements
private void createRelationNode(XmiNotationElement element, Document doc, Element rootElement) {
ModelFileInfo notation = element.getNotation();
String href = notation.getFileNameNoExtension() + ".uml#" + element.getId();
// Build class
XmiElement xmiElement = notation.getXmiElementFromHref(href);
Element parentElement = generateElementAndChildren(xmiElement.getParentElem(), doc, TAG_ELEMENT);
// Check if we need to override Target attribute if it doesn't exist
String target = parentElement.getAttribute(ATTRIBUTE_TARGET);
if (!mapElementToChildren.containsValue(target)) {
String intendedElement = mapClass2Ids.get(element.getId());
parentElement.setAttribute(ATTRIBUTE_TARGET, mapElementToChildren.get(intendedElement));
}
// Check if we need to override Source attribute
if (mapParentToSource.containsKey(element.getId())) {
String intendedSource = mapParentToSource.get(element.getId());
parentElement.setAttribute(ATTRIBUTE_SOURCE, mapElementToChildren.get(intendedSource));
}
Element elementTag = doc.createElement(TAG_ELEMENT);
for (Attribute attribute : xmiElement.getAttrib()) {
if (attribute.getName().equals(ATTRIBUTE_HREF)) {
elementTag.setAttribute(attribute.getName(), ClassMergeUtility.buildHref(element, newFileName));
} else {
elementTag.setAttribute(attribute.getName(), attribute.getValue());
}
}
parentElement.appendChild(elementTag);
rootElement.appendChild(parentElement);
}
// Generate children tag elements
private void createAssociationNode(XmiNotationElement element, Document doc, Element rootElement) {
ModelFileInfo notation = element.getNotation();
String href = notation.getFileNameNoExtension() + ".uml#" + element.getId();
// Build class
XmiElement xmiElement = notation.getXmiElementFromHref(href);
Element parentElement = generateElementAndChildren(xmiElement.getParentElem(), doc, TAG_ELEMENT);
parentElement.setAttribute(ATTRIBUTE_TARGET, mapElementToChildren.get(element.getTarget()));
parentElement.setAttribute(ATTRIBUTE_SOURCE, mapElementToChildren.get(element.getSource()));
Element elementTag = doc.createElement(TAG_ELEMENT);
for (Attribute attribute : xmiElement.getAttrib()) {
if (attribute.getName().equals(ATTRIBUTE_HREF)) {
elementTag.setAttribute(attribute.getName(), ClassMergeUtility.buildHref(element, newFileName));
} else {
elementTag.setAttribute(attribute.getName(), attribute.getValue());
}
}
parentElement.appendChild(elementTag);
rootElement.appendChild(parentElement);
}
// Generate children tag elements
private Element generateChildren(XmiElement xmiElement, Document doc, XmiNotationElement notationElement) {
Element element;
switch(xmiElement.getAttributeValue(ATTRIBUTE_TYPE)) {
case TYPE_VALUE_ATTRIBUTE:
element = generateElementAndChildren(xmiElement, doc, TAG_ELEMENT + TAG_CHILDREN);
appendAttributeElements(element, doc, notationElement);
break;
case TYPE_VALUE_OPERATION:
element = generateElementAndChildren(xmiElement, doc, TAG_ELEMENT + TAG_CHILDREN);
appendOperationElements(element, doc, notationElement);
break;
default:
element = generateElement(xmiElement, doc);
}
return element;
}
private void appendAttributeElements(Element parentElement, Document doc, XmiNotationElement notationElement) {
for (XmiNotationElement childElement : ClassMergeUtility.getNotationElements(notationElement, XmiNotationElement.TYPE_ATTRIBUTE)) {
ModelFileInfo notation = childElement.getNotation();
String href = ClassMergeUtility.buildHref(childElement.getId(), notation.getFileNameNoExtension());
XmiElement xmiElement = notation.getXmiElementFromHref(href);
XmiElement parentXmiElement = xmiElement.getParentElem();
Element elementTag = doc.createElement(TAG_ELEMENT);
for (Attribute attribute : xmiElement.getAttrib()) {
if (attribute.getName().equals(ATTRIBUTE_HREF)) {
elementTag.setAttribute(attribute.getName(), ClassMergeUtility.buildHref(childElement, newFileName));
} else {
elementTag.setAttribute(attribute.getName(), attribute.getValue());
}
}
Element attributeChild = generateElementAndChildren(parentXmiElement, doc, TAG_ELEMENT);
attributeChild.appendChild(elementTag);
parentElement.appendChild(attributeChild);
}
}
private void appendOperationElements(Element parentElement, Document doc, XmiNotationElement notationElement) {
for (XmiNotationElement childElement : ClassMergeUtility.getNotationElements(notationElement, XmiNotationElement.TYPE_OPERATION)) {
ModelFileInfo notation = childElement.getNotation();
String href = ClassMergeUtility.buildHref(childElement.getId(), notation.getFileNameNoExtension());
XmiElement xmiElement = notation.getXmiElementFromHref(href);
Element elementTag = doc.createElement(TAG_ELEMENT);
for (Attribute attribute : xmiElement.getAttrib()) {
if (attribute.getName().equals(ATTRIBUTE_HREF)) {
elementTag.setAttribute(attribute.getName(), ClassMergeUtility.buildHref(childElement, newFileName));
} else {
elementTag.setAttribute(attribute.getName(), attribute.getValue());
}
}
XmiElement parentXmiElement = xmiElement.getParentElem();
Element operationChild = generateElementAndChildren(parentXmiElement, doc, TAG_ELEMENT);
operationChild.appendChild(elementTag);
parentElement.appendChild(operationChild);
}
}
// Default method to generate an element and its children
private Element generateElement(XmiElement xmiElement, Document doc) {
Element element = doc.createElement(xmiElement.getElementName());
for (Attribute attribute : xmiElement.getAttrib()) {
if (attribute.getName().equals(ATTRIBUTE_XMI_ID) && mapClass2Ids.containsKey(attribute.getValue())) {
element.setAttribute(attribute.getName(), mapClass2Ids.get(attribute.getValue()));
} else {
element.setAttribute(attribute.getName(), attribute.getValue());
}
}
return element;
}
// Default method to generate an element and its children
private Element generateElementAndChildren(XmiElement xmiElement, Document doc) {
Element element = doc.createElement(xmiElement.getElementName());
for (Attribute attribute : xmiElement.getAttrib()) {
element.setAttribute(attribute.getName(), attribute.getValue());
}
for (XmiElement childElement : xmiElement.getChildElemList()) {
element.appendChild(generateElementAndChildren(childElement, doc));
}
return element;
}
// Generate element and children elements, but skips elements that has a tag that is in containsSkip
private Element generateElementAndChildren(XmiElement xmiElement, Document doc, String skipTag) {
Element element = doc.createElement(xmiElement.getElementName());
for (Attribute attribute : xmiElement.getAttrib()) {
element.setAttribute(attribute.getName(), attribute.getValue());
}
for (XmiElement childElement : xmiElement.getChildElemList()) {
// Skip element tags
if (!skipTag.isEmpty() && skipTag.contains(childElement.getElementName())) {
continue;
}
element.appendChild(generateElementAndChildren(childElement, doc, skipTag));
}
return element;
}
public File GenerateFile(String fileName) {
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer;
try {
transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(umlDoc);
File file = new File("C:\\temp\\" + fileName + ".notation");
StreamResult result = new StreamResult(file);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(source, result);
System.out.println("notation file created!");
return file;
} catch (TransformerException e) {
System.out.println("Failed notation file!");
e.printStackTrace();
}
return null;
}
}