blob: fe347f397d3707dd7575f97e158c0c1e848deeef [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 David A Carlson.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* David A Carlson (XMLmodeling.com) - initial API and implementation
*
* $Id$
*******************************************************************************/
package org.eclipse.mdht.uml.cda.dita;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.compare.rangedifferencer.IRangeComparator;
import org.eclipse.compare.rangedifferencer.RangeDifference;
import org.eclipse.compare.rangedifferencer.RangeDifferencer;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.mdht.uml.cda.core.profile.LogicalConstraint;
import org.eclipse.mdht.uml.cda.core.util.CDACommonUtils;
import org.eclipse.mdht.uml.cda.core.util.CDAModelUtil;
import org.eclipse.mdht.uml.cda.core.util.CDAProfileUtil;
import org.eclipse.mdht.uml.cda.core.util.ClinicalDocumentCreator;
import org.eclipse.mdht.uml.cda.core.util.InstanceGenerator;
import org.eclipse.mdht.uml.cda.core.util.ModelStatus;
import org.eclipse.mdht.uml.cda.core.util.RIMModelUtil;
import org.eclipse.mdht.uml.cda.dita.internal.Logger;
import org.eclipse.mdht.uml.common.util.NamedElementComparator;
import org.eclipse.mdht.uml.common.util.PropertyComparator;
import org.eclipse.mdht.uml.common.util.UMLUtil;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.DirectedRelationship;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Substitution;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.util.UMLSwitch;
public class TransformClassContent extends TransformAbstract {
private InstanceGenerator instanceGenerator;
private TableGenerator tableGenerator;
public TransformClassContent(DitaTransformerOptions options) {
super(options);
if (Platform.getBundle("org.eclipse.mdht.uml.cda") != null) {
instanceGenerator = new InstanceGenerator();
tableGenerator = new TableGenerator();
}
}
private void appendAggregateRules(PrintWriter writer, Class umlClass) {
Package xrefSource = UMLUtil.getTopPackage(umlClass);
List<Classifier> allParents = new ArrayList<Classifier>(umlClass.allParents());
allParents.add(0, umlClass);
List<Property> allProperties = new ArrayList<Property>();
List<Property> allAssociations = new ArrayList<Property>();
List<Property> allAttributes = new ArrayList<Property>();
List<Constraint> allConstraints = new ArrayList<Constraint>();
// categorize constraints by constrainedElement name
List<Constraint> unprocessedConstraints = new ArrayList<Constraint>();
// propertyName -> constraints
Map<String, List<Constraint>> constraintMap = new HashMap<String, List<Constraint>>();
// constraint -> sub-constraints
Map<Constraint, List<Constraint>> subConstraintMap = new HashMap<Constraint, List<Constraint>>();
for (Constraint constraint : umlClass.getOwnedRules()) {
unprocessedConstraints.add(constraint);
if (CDAProfileUtil.getLogicalConstraint(constraint) == null) {
for (Element element : constraint.getConstrainedElements()) {
if (element instanceof Property) {
String name = ((Property) element).getName();
List<Constraint> rules = constraintMap.get(name);
if (rules == null) {
rules = new ArrayList<Constraint>();
constraintMap.put(name, rules);
}
rules.add(constraint);
} else if (element instanceof Constraint) {
Constraint subConstraint = (Constraint) element;
List<Constraint> rules = subConstraintMap.get(subConstraint);
if (rules == null) {
rules = new ArrayList<Constraint>();
subConstraintMap.put(subConstraint, rules);
}
rules.add(constraint);
}
}
}
}
// process parents in reverse order, CDA base class first
for (int i = allParents.size() - 1; i >= 0; i--) {
Class parent = (Class) allParents.get(i);
for (Property property : parent.getOwnedAttributes()) {
if (property.getAssociation() != null) {
allAssociations.add(property);
} else {
// if list contains this property name, replace it; else append
int index = findProperty(allProperties, property.getName());
if (index >= 0) {
allProperties.set(index, property);
} else {
allProperties.add(property);
}
}
}
// Remove participants in logical constraints that do not have a severity
for (Constraint constraint : parent.getOwnedRules()) {
LogicalConstraint logicConstraint = CDAProfileUtil.getLogicalConstraint(constraint);
if (logicConstraint != null) {
for (Element constrainedElement : constraint.getConstrainedElements()) {
if (constrainedElement instanceof Property) {
Property property = (Property) constrainedElement;
String validation = CDAModelUtil.getValidationKeyword(constrainedElement);
if (validation == null && property.getAssociation() != null) {
validation = CDAModelUtil.getValidationKeyword(property.getAssociation());
}
if (validation == null) {
allProperties.remove(constrainedElement);
allAttributes.remove(constrainedElement);
}
}
}
}
}
}
Iterator<Property> propertyIterator = allProperties.iterator();
while (propertyIterator.hasNext()) {
Property property = propertyIterator.next();
if (CDAModelUtil.isCDAModel(property) && property.getLower() == 0) {
// include only required CDA class properties
propertyIterator.remove();
}
}
Iterator<Property> associationIterator = allAssociations.iterator();
while (associationIterator.hasNext()) {
Property property = associationIterator.next();
if (CDAModelUtil.isCDAModel(property) && property.getLower() == 0) {
// include only required CDA class properties
associationIterator.remove();
}
}
/*
* Include only associations that are not redefined in a subclass.
* TODO There must be a better way... use UML property redefinition in model.
*/
List<Classifier> endTypes = new ArrayList<Classifier>();
for (Property property : allAssociations) {
endTypes.add((Classifier) property.getType());
}
for (int index = 0; index < allAssociations.size(); index++) {
Classifier classifier = endTypes.get(index);
boolean hasSubclass = false;
List<DirectedRelationship> specializations = classifier.getTargetDirectedRelationships(
UMLPackage.Literals.GENERALIZATION);
for (DirectedRelationship relationship : specializations) {
Classifier specific = ((Generalization) relationship).getSpecific();
if (endTypes.contains(specific)) {
hasSubclass = true;
break;
}
}
if (!hasSubclass) {
allProperties.add(allAssociations.get(index));
}
}
// aggregate constraints
for (int i = allParents.size() - 1; i >= 0; i--) {
Class parent = (Class) allParents.get(i);
if (!CDAModelUtil.isCDAModel(parent)) {
for (Constraint constraint : parent.getOwnedRules()) {
allConstraints.add(constraint);
}
}
}
writer.println("<ol id=\"aggregate\">");
// use i>0 to omit this class
for (int i = allParents.size() - 1; i > 0; i--) {
Class parent = (Class) allParents.get(i);
if (!RIMModelUtil.isRIMModel(parent) && !CDAModelUtil.isCDAModel(parent) &&
!CDAModelUtil.isDatatypeModel(parent)) {
String message = CDAModelUtil.computeGeneralizationConformanceMessage(parent, true, xrefSource);
if (message.length() > 0) {
writer.println("<li>" + message + "</li>");
}
}
}
for (Property property : allProperties) {
if (CDAModelUtil.isXMLAttribute(property)) {
allAttributes.add(property);
}
}
allProperties.removeAll(allAttributes);
Collections.sort(allAttributes, new NamedElementComparator());
// XML attributes
for (Property property : allAttributes) {
writer.println("<li>" + CDAModelUtil.computeConformanceMessage(property, true));
appendPropertyRules(writer, property, constraintMap, subConstraintMap, unprocessedConstraints);
appendPropertyComments(writer, property);
writer.println("</li>");
}
// XML elements
for (Property property : allProperties) {
writer.println("<li>" + CDAModelUtil.computeConformanceMessage(property, true));
appendPropertyRules(writer, property, constraintMap, subConstraintMap, unprocessedConstraints);
if (!(property.getType().getOwner() instanceof Class)) {
// comments are output preceding inline classes
appendPropertyComments(writer, property);
}
writer.println("</li>");
}
for (Constraint constraint : allConstraints) {
writer.println("<li>" + CDAModelUtil.computeConformanceMessage(constraint, true)
// + " " + modelPrefix(constraint)
+ "</li>");
}
// <ol> cannot be empty
if (allAttributes.isEmpty() && allProperties.isEmpty() && allConstraints.isEmpty()) {
writer.println("<li></li>");
}
writer.println("</ol>");
}
private void appendBody(PrintWriter writer, Class umlClass) {
writer.println("<body>");
appendKnownSubclasses(writer, umlClass);
appendClassDocumentation(writer, umlClass);
appendConformanceRules(writer, umlClass);
appendAggregateRules(writer, umlClass);
// if (transformerOptions.isIncludeTableView()) {
// System.err.println("AppendBody " + umlClass);
appendTable(writer, umlClass);
// }
appendExample(writer, umlClass);
appendChanges(writer, umlClass);
writer.println("<p><ph id=\"classformalname\">" + TransformAbstract.getPublicationName(umlClass) + "</ph></p>");
Class cdaClass = CDAModelUtil.getCDAClass(umlClass);
String cdaClassName = cdaClass != null
? cdaClass.getName()
: "MISSING_CDA_CLASS";
if (cdaClass != null) {
writer.print("<p id=\"shortdesc\">");
if (!umlClass.equals(cdaClass)) {
writer.print(
"[" + ClinicalDocumentCreator.withoutDigits(cdaClassName) + ": templateId <tt>" +
CDAModelUtil.getTemplateId(umlClass) + "</tt>]");
}
writer.println("</p>");
}
writer.println("</body>");
writer.println("</topic>");
}
private void appendKnownSubclasses(PrintWriter writer, Class umlClass) {
writer.println("<section id=\"knownSubclasses\">");
List<Classifier> subclasses = UMLUtil.getSpecializations(umlClass);
if (subclasses.size() > 0) {
writer.print("<p>Known Subclasses: ");
for (Iterator<Classifier> iterator = subclasses.iterator(); iterator.hasNext();) {
Classifier subclass = iterator.next();
if (subclass instanceof Class && (!(subclass.getOwner() instanceof Class))) {
Package xrefSource = UMLUtil.getTopPackage(subclass);
String xref = CDAModelUtil.computeXref(xrefSource, subclass);
String format = xref != null && xref.endsWith(".html")
? "format=\"html\" "
: "";
writer.append("<xref " + format + "href=\"" + xref + "\">");
writer.append(TransformAbstract.getPublicationName(subclass));
writer.append("</xref>");
if (iterator.hasNext()) {
writer.print(", ");
}
}
}
writer.println("</p>");
}
writer.println("</section>");
}
private void appendClassDocumentation(PrintWriter writer, Class umlClass) {
writer.println("<section id=\"description\">");
// TODO if blank line, wrap before and after contents in <p>
for (Comment comment : umlClass.getOwnedComments()) {
String body = CDAModelUtil.fixNonXMLCharacters(comment.getBody().trim());
writer.println("<p>" + body + "</p>");
}
writer.println("</section>");
}
private void appendConformanceRules(PrintWriter writer, Class umlClass) {
writer.println("<ol id=\"conformance\">");
Property templateIdProperty = null;
if (transformerOptions.isPrintAssigningAuthorityName()) {
templateIdProperty = CDACommonUtils.createTemplateIdProperty(umlClass);
}
if (templateIdProperty != null) {
writer.println("<li>" + CDAModelUtil.computeConformanceMessage(templateIdProperty, true) + "</li>");
// remove property as it is already printed and is not required anymore
umlClass.getOwnedAttributes().remove(templateIdProperty);
}
if (CDAModelUtil.getTemplateId(umlClass) != null && templateIdProperty == null) {
writer.println("<li>" + CDAModelUtil.computeConformanceMessage(umlClass, true) + "</li>");
}
boolean hasRules = false;
for (Generalization generalization : umlClass.getGeneralizations()) {
Classifier general = generalization.getGeneral();
if (!RIMModelUtil.isRIMModel(general) && !CDAModelUtil.isCDAModel(general) &&
!CDAModelUtil.isDatatypeModel(general)) {
String message = CDAModelUtil.computeConformanceMessage(generalization, true);
if (message.length() > 0) {
hasRules = true;
writer.println("<li>" + message + "</li>");
}
}
}
// categorize constraints by constrainedElement name
List<Constraint> unprocessedConstraints = new ArrayList<Constraint>();
// propertyName -> constraints
Map<String, List<Constraint>> constraintMap = new HashMap<String, List<Constraint>>();
// constraint -> sub-constraints
Map<Constraint, List<Constraint>> subConstraintMap = new HashMap<Constraint, List<Constraint>>();
for (Constraint constraint : umlClass.getOwnedRules()) {
unprocessedConstraints.add(constraint);
for (Element element : constraint.getConstrainedElements()) {
if (CDAProfileUtil.getLogicalConstraint(constraint) == null) {
if (element instanceof Property) {
if (!CDAModelUtil.hasOwnPDFSection((Property) element)) {
unprocessedConstraints.remove(constraint);
continue;
}
String name = ((Property) element).getName();
List<Constraint> rules = constraintMap.get(name);
if (rules == null) {
rules = new ArrayList<Constraint>();
constraintMap.put(name, rules);
}
rules.add(constraint);
} else if (element instanceof Constraint) {
Constraint subConstraint = (Constraint) element;
List<Constraint> rules = subConstraintMap.get(subConstraint);
if (rules == null) {
rules = new ArrayList<Constraint>();
subConstraintMap.put(subConstraint, rules);
}
rules.add(constraint);
}
}
}
}
List<Property> allProperties = new ArrayList<Property>(umlClass.getOwnedAttributes());
List<Property> allAttributes = new ArrayList<Property>();
for (Property property : allProperties) {
if (CDAModelUtil.isXMLAttribute(property)) {
allAttributes.add(property);
}
// Check to see if the property is part of a logical constraint - if so do not create process as a property
}
for (Constraint constraint : umlClass.getOwnedRules()) {
LogicalConstraint logicConstraint = CDAProfileUtil.getLogicalConstraint(constraint);
if (logicConstraint != null) {
for (Element constrainedElement : constraint.getConstrainedElements()) {
if (constrainedElement instanceof Property) {
Property property = (Property) constrainedElement;
String validation = CDAModelUtil.getValidationKeyword(constrainedElement);
if (validation == null && property.getAssociation() != null) {
validation = CDAModelUtil.getValidationKeyword(property.getAssociation());
}
if (validation == null) {
allProperties.remove(constrainedElement);
allAttributes.remove(constrainedElement);
}
}
}
}
}
allProperties.removeAll(allAttributes);
Collections.sort(allAttributes, new NamedElementComparator());
// XML attributes
for (Property property : allAttributes) {
if (!CDAModelUtil.hasOwnPDFSection(property)) {
continue;
}
hasRules = true;
writer.println("<li>" + CDAModelUtil.computeConformanceMessage(property, true));
appendPropertyComments(writer, property);
appendPropertyRules(writer, property, constraintMap, subConstraintMap, unprocessedConstraints);
writer.println("</li>");
}
Collections.sort(allProperties, new PropertyComparator());
// XML elements
for (Property property : allProperties) {
if (!CDAModelUtil.hasOwnPDFSection(property)) {
continue;
}
hasRules = true;
writer.println("<li>");
String extendedConformanceMessage = CDAModelUtil.computeConformanceMessage(property, true);
if (!(property.getType().getOwner() instanceof Class)) {
// comments are output preceding inline classes
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
appendPropertyComments(printWriter, property);
extendedConformanceMessage = extendedConformanceMessage + stringWriter.getBuffer().toString();
}
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
appendPropertyRules(printWriter, property, constraintMap, subConstraintMap, unprocessedConstraints);
extendedConformanceMessage = meltOL(extendedConformanceMessage, stringWriter.getBuffer().toString());
writer.println(extendedConformanceMessage);
writer.println("</li>");
}
for (Constraint constraint : unprocessedConstraints) {
hasRules = true;
writer.println("<li>" + CDAModelUtil.computeConformanceMessage(constraint, true) + "</li>");
}
if (!hasRules) {
writer.println("<li></li>");
}
writer.println("</ol>");
}
/**
* @param a
* @param b
* @return returns the concatenation of <code>a</code> and <code>b</code>; however, if <code>a</code> and <code>b</code> ends and starts an
* unordered list respectively, joins those two lists
*/
public static String meltOL(String a, String b) {
if (a.endsWith("</ol>") && b.startsWith("<ol>")) {
return a.substring(0, a.length() - "</ol>".length()) + b.substring("<ol>".length());
}
return a + b;
}
private void appendExample(PrintWriter writer, Class umlClass) {
writer.print("<codeblock id=\"example\" outputclass=\"language-xml\"><![CDATA[");
if (instanceGenerator != null) {
int exampleDepth = transformerOptions.getExampleDepth();
transformerOptions.isIncludeTableView();
String xmlGeneratorType = transformerOptions.getXmlGeneratorType();
if (xmlGeneratorType == null) {
xmlGeneratorType = "custom-if-data-present";
}
EObject eObject = "custom-only".equals(xmlGeneratorType)
? null
: instanceGenerator.createInstance(
umlClass, exampleDepth > 0
? exampleDepth
: 2);
if (eObject == null && !"original-only".equals(xmlGeneratorType) || "custom".equals(xmlGeneratorType) ||
"custom-if-data-present".equals(xmlGeneratorType)) {
ArrayList<ModelStatus> statuses = new ArrayList<ModelStatus>();
ClinicalDocumentCreator creator = new ClinicalDocumentCreator(
null, umlClass.eResource().getResourceSet(), statuses);
creator.enableSampleData(true);
creator.enableSampleDataExpansion(true);
Collection<Property> props = Collections.emptyList();
EObject newObject = creator.initializeSnippet(umlClass, props);
if (newObject == null && eObject == null && !"original".equals(xmlGeneratorType)) {
writer.println("Error: Custom XML generator could not create XML sample");
for (ModelStatus status : statuses) {
writer.println("Error code " + status.getCode() + ": " + status.getMessage());
}
writer.println("]]></codeblock>");
return;
}
if (newObject != null && (eObject == null || "custom".equals(xmlGeneratorType) ||
"custom-if-data-present".equals(xmlGeneratorType) && creator.getSampler().isCustomDataUsed())) {
String xml = creator.toXMLString(newObject, umlClass);
writer.write(xml);
writer.println("]]></codeblock>");
for (ModelStatus status : statuses) {
writer.println("<!--Error code " + status.getCode() + ": " + status.getMessage() + "-->");
}
return;
}
}
if (eObject != null) {
instanceGenerator.save(eObject, writer);
} else {
Logger.log(Logger.ERROR, "Error: Missing Runtime Class for UML Class " + umlClass.getQualifiedName());
writer.print("Error: Missing Runtime Class");
}
} else {
writer.print("TODO: XML document snippet");
}
writer.println("]]></codeblock>");
}
private void appendHeader(PrintWriter writer, Class umlClass) {
writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
writer.println("<!DOCTYPE topic PUBLIC \"-//OASIS//DTD DITA Topic//EN\" \"topic.dtd\">");
writer.println("<topic id=\"classId\" xml:lang=\"en-us\">");
writer.print("<title>");
writer.print(TransformAbstract.getPublicationName(umlClass));
writer.print(" - conformance rules");
writer.println("</title>");
Class cdaClass = CDAModelUtil.getCDAClass(umlClass);
String prefix = getExtensionName(cdaClass);
String cdaClassName = cdaClass != null
? cdaClass.getName()
: "MISSING_CDA_CLASS";
writer.print("<shortdesc id=\"shortdesc\">");
if (umlClass.isAbstract()) {
writer.print("<i>Abstract</i> ");
}
if (cdaClass != null && !umlClass.equals(cdaClass)) {
writer.print(
"[" + prefix + ClinicalDocumentCreator.withoutDigits(cdaClassName) + ": templateId <tt>" +
CDAModelUtil.getTemplateId(umlClass) + "</tt>]");
}
writer.println("</shortdesc>");
writer.println("<prolog id=\"prolog\">");
if (cdaClass != null) {
writer.println("<metadata><category>" + cdaClassName + "</category></metadata>");
writer.println("<resourceid id=\"" + CDAModelUtil.getTemplateId(umlClass) + "\"/>");
}
writer.println("</prolog>");
}
private String getExtensionName(Class cdaClass) {
String name = CDAModelUtil.getNameSpacePrefix(cdaClass);
return name == null || name.isEmpty()
? ""
: name + ":";
}
private void appendPropertyComments(PrintWriter writer, Property property) {
Association association = property.getAssociation();
if (association != null && association.getOwnedComments().size() > 0) {
writer.append("<ol>");
for (Comment comment : association.getOwnedComments()) {
writer.append("<li><p>");
writer.append(CDAModelUtil.fixNonXMLCharacters(comment.getBody()));
writer.append("</p></li>");
}
writer.append("</ol>");
}
if (property.getOwnedComments().size() > 0) {
for (Comment comment : property.getOwnedComments()) {
writer.append("<p>");
writer.append(CDAModelUtil.fixNonXMLCharacters(comment.getBody()));
writer.append("</p>");
}
}
}
private void appendPropertyRules(PrintWriter writer, Property property, Map<String, List<Constraint>> constraintMap,
Map<Constraint, List<Constraint>> subConstraintMap, List<Constraint> unprocessedConstraints) {
// association typeCode and property type
String assocConstraints = "";
if (property.getAssociation() != null) {
assocConstraints = CDAModelUtil.computeAssociationConstraints(property, true);
}
StringBuffer ruleConstraints = new StringBuffer();
List<Constraint> rules = constraintMap.get(property.getName());
if (rules != null && !rules.isEmpty()) {
for (Constraint constraint : rules) {
unprocessedConstraints.remove(constraint);
ruleConstraints.append("\n<li>" + CDAModelUtil.computeConformanceMessage(constraint, true));
appendSubConstraintRules(ruleConstraints, constraint, subConstraintMap, unprocessedConstraints);
// List<Constraint> subConstraints = subConstraintMap.get(constraint);
// if (subConstraints != null && subConstraints.size() > 0) {
// ruleConstraints.append("<ol>");
// for (Constraint subConstraint : subConstraints) {
// unprocessedConstraints.remove(subConstraint);
// ruleConstraints.append("\n<li>" + CDAModelUtil.computeConformanceMessage(subConstraint, true) + "</li>");
// }
// ruleConstraints.append("</ol>");
// }
ruleConstraints.append("</li>");
}
}
if (assocConstraints.length() > 0 || ruleConstraints.length() > 0) {
// writer.append(", such that ");
// writer.append(property.upperBound()==1 ? "it" : "each");
writer.append("<ol>");
writer.append(assocConstraints);
writer.append(ruleConstraints);
writer.append("</ol>");
}
}
private void appendSubConstraintRules(StringBuffer ruleConstraints, Constraint constraint,
Map<Constraint, List<Constraint>> subConstraintMap, List<Constraint> unprocessedConstraints) {
List<Constraint> subConstraints = subConstraintMap.get(constraint);
if (subConstraints != null && subConstraints.size() > 0) {
ruleConstraints.append("<ol>");
for (Constraint subConstraint : subConstraints) {
unprocessedConstraints.remove(subConstraint);
ruleConstraints.append("\n<li>" + CDAModelUtil.computeConformanceMessage(subConstraint, true));
appendSubConstraintRules(ruleConstraints, subConstraint, subConstraintMap, unprocessedConstraints);
ruleConstraints.append("</li>");
}
ruleConstraints.append("</ol>");
}
}
@Override
public Object caseClass(Class umlClass) {
String normalizedClassName = normalizeCodeName(umlClass.getName());
String pathFolder = "classes";
IPath filePath = transformerOptions.getOutputPath().append(pathFolder).addTrailingSeparator().append(
"generated").addTrailingSeparator().append("_" + normalizedClassName).addFileExtension("dita");
return writeClassToFile(umlClass, filePath);
}
public Object writeClassToFile(Class umlClass, IPath filePath) {
File file = filePath.toFile();
PrintWriter writer = null;
try {
file.createNewFile();
writer = new PrintWriter(file);
appendHeader(writer, umlClass);
appendBody(writer, umlClass);
} catch (FileNotFoundException e) {
Logger.logException(e);
} catch (IOException e1) {
Logger.logException(e1);
} finally {
if (writer != null) {
writer.close();
}
}
return umlClass;
}
private int findProperty(List<Property> properties, String name) {
if (name != null) {
for (int i = 0; i < properties.size(); i++) {
if (name.equals(properties.get(i).getName())) {
return i;
}
}
}
return -1;
}
private String modelPrefix(NamedElement element) {
StringBuffer prefix = new StringBuffer();
String modelPrefix = CDAModelUtil.getModelPrefix(element);
if (modelPrefix != null && modelPrefix.length() > 0) {
prefix.append("[");
prefix.append(modelPrefix);
prefix.append("] ");
}
return prefix.toString();
}
private void appendTable(PrintWriter writer, Class umlClass) {
if (tableGenerator != null) {
String table = tableGenerator.createTable(umlClass);
if (table != null && table.length() > 0) {
writer.println(table);
}
table = tableGenerator.createTable2(umlClass);
if (table != null && table.length() > 0) {
writer.println(table);
}
}
}
private void appendChanges(PrintWriter writer, Class umlClass) {
writer.println("<section id=\"changes\">");
;
for (Substitution substitution : umlClass.getSubstitutions()) {
for (NamedElement ne : substitution.getSuppliers()) {
if (ne instanceof Class) {
appendChangeLog(writer, umlClass, (Class) ne);
}
}
}
writer.println("</section>");
}
private static void composeAllConformanceMessages(Class element, final PrintWriter writer, final boolean markup) {
//
// for (Generalization generalization : element.getGeneralizations()) {
// if (generalization.getGeneral() instanceof Class) {
// composeAllConformanceMessages((Class) generalization.getGeneral(), writer, false);
// }
//
// }
final TreeIterator<EObject> iterator = EcoreUtil.getAllContents(Collections.singletonList(element));
while (iterator != null && iterator.hasNext()) {
EObject child = iterator.next();
UMLSwitch<Object> umlSwitch = new UMLSwitch<Object>() {
@Override
public Object caseAssociation(Association association) {
iterator.prune();
return association;
}
@Override
public Object caseClass(Class umlClass) {
String message = CDAModelUtil.computeConformanceMessage(umlClass, markup);
writer.println(message);
return umlClass;
}
@Override
public Object caseGeneralization(Generalization generalization) {
String message = CDAModelUtil.computeConformanceMessage(generalization, markup);
if (message.length() > 0) {
writer.println(message);
}
return generalization;
}
@Override
public Object caseProperty(Property property) {
String message = CDAModelUtil.computeConformanceMessage(property, markup);
if (message.length() > 0) {
writer.println(message);
}
return property;
}
@Override
public Object caseConstraint(Constraint constraint) {
String message = CDAModelUtil.computeConformanceMessage(constraint, markup);
if (message.length() > 0) {
writer.println(message);
}
return constraint;
}
};
umlSwitch.doSwitch(child);
}
}
class LineComparator implements IRangeComparator {
private String[] fLines;
public LineComparator(InputStream is) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
ArrayList<String> ar = new ArrayList<>();
while ((line = br.readLine()) != null) {
ar.add(line);
}
// It is the responsibility of the caller to close the stream
fLines = ar.toArray(new String[ar.size()]);
}
String getLine(int ix) {
return fLines[ix];
}
/*
* (non-Javadoc)
*
* @see org.eclipse.compare.rangedifferencer.IRangeComparator#getRangeCount()
*/
public int getRangeCount() {
return fLines.length;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.compare.rangedifferencer.IRangeComparator#rangesEqual(int, org.eclipse.compare.rangedifferencer.IRangeComparator, int)
*/
public boolean rangesEqual(int thisIndex, IRangeComparator other, int otherIndex) {
String s1 = fLines[thisIndex];
String s2 = ((LineComparator) other).fLines[otherIndex];
return s1.equals(s2);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.compare.rangedifferencer.IRangeComparator#skipRangeComparison(int, int,
* org.eclipse.compare.rangedifferencer.IRangeComparator)
*/
public boolean skipRangeComparison(int length, int maxLength, IRangeComparator other) {
return false;
}
}
public IStatus appendChanges(PrintWriter writer, InputStream target, InputStream other) {
IProgressMonitor monitor = null;
LineComparator t, o;
try {
t = new LineComparator(target);
o = new LineComparator(other);
} catch (UnsupportedEncodingException e) {
return null;
// return new Status(IStatus.ERROR, CompareUI.PLUGIN_ID, 1, MergeMessages.TextAutoMerge_inputEncodingError, e);
} catch (IOException e) {
return null;
// return new Status(IStatus.ERROR, CompareUI.PLUGIN_ID, 1, e.getMessage(), e);
}
// try {
String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
if (lineSeparator == null) {
lineSeparator = "\n"; //$NON-NLS-1$
}
RangeDifference[] diffs = RangeDifferencer.findRanges(monitor, t, o);
writer.append("<li>");
writer.println("<b>Modifications</b>");
writer.append("</li>");
for (int i = 0; i < diffs.length; i++) {
RangeDifference rd = diffs[i];
switch (rd.kind()) {
case RangeDifference.RIGHT:
for (int j = rd.rightStart(); j < rd.rightEnd(); j++) {
String s = o.getLine(j);
writer.append("<li>");
writer.println(s);
writer.append("</li>");
}
break;
default:
break;
}
}
writer.append("<li>");
writer.println("<b>Additions</b>");
writer.append("</li>");
for (int i = 0; i < diffs.length; i++) {
RangeDifference rd = diffs[i];
switch (rd.kind()) {
case RangeDifference.LEFT:
for (int j = rd.leftStart(); j < rd.leftEnd(); j++) {
String s = t.getLine(j);
writer.append("<li>");
writer.println(s);
writer.append("</li>");
}
break;
default:
break;
}
}
return Status.OK_STATUS;
}
void appendChangeLog(PrintWriter writer, Class source, Class substitute) {
writer.println("<p>");
// CDAModelUtil.get
writer.println("Change Log from " + CDAModelUtil.getModelPrefix(substitute) + "::" + substitute.getName());
writer.println("</p>");
writer.println("<p id=\"" + substitute.getName() + "\" >");
writer.append("<ol>");
StringWriter leftsw = new StringWriter();
PrintWriter leftpw = new PrintWriter(leftsw);
composeAllConformanceMessages(source, leftpw, false);
StringWriter rightsw = new StringWriter();
PrintWriter rightpw = new PrintWriter(rightsw);
composeAllConformanceMessages(substitute, rightpw, false);
InputStream sourceStream = new ByteArrayInputStream(leftsw.getBuffer().toString().getBytes());
InputStream substitueStream = new ByteArrayInputStream(rightsw.getBuffer().toString().getBytes());
appendChanges(writer, sourceStream, substitueStream);
writer.append("</ol>");
writer.println("</p>");
}
}