View Javadoc
1   package xuml.tools.diagram;
2   
3   import static com.google.common.base.Optional.absent;
4   import static com.google.common.base.Optional.of;
5   
6   import java.io.IOException;
7   import java.math.BigInteger;
8   import java.util.ArrayList;
9   import java.util.List;
10  
11  import org.apache.commons.io.IOUtils;
12  
13  import com.google.common.base.Optional;
14  
15  import jakarta.xml.bind.JAXBElement;
16  import xuml.tools.miuml.metamodel.jaxb.AssociativeReference;
17  import xuml.tools.miuml.metamodel.jaxb.Attribute;
18  import xuml.tools.miuml.metamodel.jaxb.BinaryAssociation;
19  import xuml.tools.miuml.metamodel.jaxb.Class;
20  import xuml.tools.miuml.metamodel.jaxb.DerivedAttribute;
21  import xuml.tools.miuml.metamodel.jaxb.Domain;
22  import xuml.tools.miuml.metamodel.jaxb.Domains;
23  import xuml.tools.miuml.metamodel.jaxb.Event;
24  import xuml.tools.miuml.metamodel.jaxb.Generalization;
25  import xuml.tools.miuml.metamodel.jaxb.IdentifierAttribute;
26  import xuml.tools.miuml.metamodel.jaxb.IndependentAttribute;
27  import xuml.tools.miuml.metamodel.jaxb.ModeledDomain;
28  import xuml.tools.miuml.metamodel.jaxb.Named;
29  import xuml.tools.miuml.metamodel.jaxb.Perspective;
30  import xuml.tools.miuml.metamodel.jaxb.Reference;
31  import xuml.tools.miuml.metamodel.jaxb.ReferentialAttribute;
32  import xuml.tools.miuml.metamodel.jaxb.Relationship;
33  import xuml.tools.miuml.metamodel.jaxb.Subsystem;
34  import xuml.tools.miuml.metamodel.jaxb.SubsystemElement;
35  import xuml.tools.miuml.metamodel.jaxb.UnaryAssociation;
36  
37  public class ClassDiagramGenerator {
38  
39      private String placeInTemplate(String divs, Optional<String> viewJson) {
40          try {
41              String template = IOUtils.toString(ClassDiagramGenerator.class
42                      .getResourceAsStream("/class-diagram-template.html"));
43              return template.replace("${xuml.divs}", divs).replace("${view.json}",
44                      viewJson.or("{}"));
45          } catch (IOException e) {
46              throw new RuntimeException(e);
47          }
48      }
49  
50      private Optional<Subsystem> getSubsystem(Domains domains, String domainName,
51              String subsystemName) {
52          for (JAXBElement<? extends Domain> domain : domains.getDomain()) {
53              if (domain.getValue() instanceof ModeledDomain
54                      && domain.getValue().getName().equals(domainName)) {
55                  ModeledDomain md = (ModeledDomain) domain.getValue();
56                  for (Subsystem ss : md.getSubsystem())
57                      if (ss.getName().equals(subsystemName))
58                          return of(ss);
59              }
60          }
61          return absent();
62      }
63  
64      public String generate(Domains domains, String domainName, String subsystemName,
65              Optional<String> viewJson) {
66          return placeInTemplate(generateDivs(getSubsystem(domains, domainName, subsystemName)),
67                  viewJson);
68      }
69  
70      public String generate(Domains domains, int domainIndex, int ssIndex,
71              Optional<String> viewJson) {
72          if (domains.getDomain().isEmpty())
73              return placeInTemplate("", Optional.<String> absent());
74          ModeledDomain md = ((ModeledDomain) domains.getDomain().get(domainIndex).getValue());
75          if (md.getSubsystem().isEmpty())
76              return placeInTemplate("", Optional.<String> absent());
77          Subsystem ss = md.getSubsystem().get(ssIndex);
78          return generate(domains, md.getName(), ss.getName(), viewJson);
79      }
80  
81      private String generateDivs(Optional<Subsystem> subsystem) {
82          if (!subsystem.isPresent())
83              return "";
84  
85          StringBuilder s = new StringBuilder();
86          for (JAXBElement<? extends SubsystemElement> element : subsystem.get()
87                  .getSubsystemElement())
88              if (element.getValue() instanceof xuml.tools.miuml.metamodel.jaxb.Class)
89                  generateClass(s, (xuml.tools.miuml.metamodel.jaxb.Class) element.getValue());
90              else if (element.getValue() instanceof Relationship) {
91                  Relationship r = (Relationship) element.getValue();
92                  if (r instanceof BinaryAssociation)
93                      generateAssociation(s, (BinaryAssociation) r, subsystem.get());
94                  else if (r instanceof UnaryAssociation)
95                      generateAssociation(s, (UnaryAssociation) r, subsystem.get());
96                  else if (r instanceof Generalization)
97                      generateGeneralization(s, (Generalization) r);
98              }
99          return s.toString();
100     }
101 
102     private void generateGeneralization(StringBuilder s, Generalization g) {
103         for (Named sp : g.getSpecializedClass())
104             s.append("<div class=\"generalization\" id=\"" + replaceSpaces(sp.getName()) + "-"
105                     + getRelationshipName(g.getRnum()) + "\" groupName=\""
106                     + getRelationshipName(g.getRnum()) + "\" superClassName=\""
107                     + replaceSpaces(g.getSuperclass()) + "\" subClassName=\""
108                     + replaceSpaces(sp.getName()) + "\"></div>\n");
109     }
110 
111     private String replaceSpaces(String s) {
112         return s.replaceAll(" ", "_");
113     }
114 
115     private void generateAssociation(StringBuilder s, BinaryAssociation r, Subsystem ss) {
116         if (r.getActivePerspective().getViewedClass()
117                 .equals(r.getPassivePerspective().getViewedClass())) {
118             System.out.println("binary association involving one class only not yet supported");
119             return;
120         }
121         s.append(
122                 "<div class=\"relationship\" id=\"" + getRelationshipName(r.getRnum())
123                         + "\" className1=\"" + r.getActivePerspective().getViewedClass()
124                                 .replaceAll(" ", "_")
125                         + "\" className2=\""
126                         + r.getPassivePerspective().getViewedClass().replaceAll(" ", "_")
127                         + "\" verbClause1=\"" + r.getActivePerspective().getPhrase()
128                         + "\" verbClause2=\"" + r.getPassivePerspective().getPhrase()
129                         + "\" multiplicity1=\""
130                         + getMultiplicityAbbreviation(r.getActivePerspective())
131                         + "\" multiplicity2=\""
132                         + getMultiplicityAbbreviation(r.getPassivePerspective()) + "\"></div>\n");
133     }
134 
135     private void generateAssociation(StringBuilder s, UnaryAssociation r, Subsystem subsystem) {
136         // TODO implement unary associations
137     }
138 
139     private String getMultiplicityAbbreviation(Perspective p) {
140         if (p.isConditional() && p.isOnePerspective())
141             return "0..1";
142         else if (!p.isConditional() && p.isOnePerspective())
143             return "1";
144         else if (p.isConditional() && !p.isOnePerspective())
145             return "*";
146         else
147             return "1..*";
148     }
149 
150     private static String getIdentifierName(BigInteger i) {
151         if (i.intValue() == 1)
152             return "I";
153         else
154             return "I" + i;
155     }
156 
157     private static String getRelationshipName(BigInteger n) {
158         return "R" + n;
159     }
160 
161     private void generateClass(StringBuilder s, xuml.tools.miuml.metamodel.jaxb.Class cls) {
162         // System.out.println("class=" + cls.getName());
163         s.append("<div id=\"" + cls.getName().replaceAll(" ", "_") + "\" class=\"cls draggable");
164 
165         BigInteger assocationClassRelationship = getAssociationClassRelationship(cls);
166 
167         if (assocationClassRelationship != null)
168             s.append(" associationClass");
169         s.append("\"");
170         if (assocationClassRelationship != null)
171             s.append(" relationshipName=\"" + getRelationshipName(assocationClassRelationship)
172                     + "\" ");
173         s.append(">\n");
174         s.append("  <div class=\"attributes\">\n");
175         for (JAXBElement<? extends Attribute> attr : cls.getAttribute()) {
176 
177             // System.out.println("attribute=" + attr.getValue().getName());
178             List<String> items = new ArrayList<String>();
179             for (IdentifierAttribute id : attr.getValue().getIdentifier())
180                 items.add(getIdentifierName(id.getNumber()));
181             if (attr.getValue() instanceof IndependentAttribute) {
182                 IndependentAttributexuml/tools/miuml/metamodel/jaxb/IndependentAttribute.html#IndependentAttribute">IndependentAttribute a = (IndependentAttribute) attr.getValue();
183                 s.append("    <div class=\"attribute\">" + a.getName() + ": " + a.getType() + " ");
184                 // if (!a.isMandatory())
185                 // items.add("O");
186             } else if (attr.getValue() instanceof ReferentialAttribute) {
187                 ReferentialAttribute r = (ReferentialAttribute) attr.getValue();
188                 Reference ref = r.getReference().getValue();
189                 items.add(getRelationshipName(ref.getRelationship()));
190                 s.append("<div class=\"attribute\">" + r.getName() + ": ");
191             } else if (attr.getValue() instanceof DerivedAttribute) {
192                 DerivedAttribute/../xuml/tools/miuml/metamodel/jaxb/DerivedAttribute.html#DerivedAttribute">DerivedAttribute d = (DerivedAttribute) attr.getValue();
193                 s.append("<div class=\"attribute\">" + "/ " + d.getName() + ": " + d.getType());
194             }
195             StringBuilder b = new StringBuilder();
196             for (String item : items) {
197                 if (b.length() > 0)
198                     b.append(",");
199                 b.append(item);
200             }
201             if (b.length() > 0)
202                 s.append("{" + b + "}");
203             s.append("</div>\n");
204         }
205         s.append("  </div>\n");
206 
207         // if (!cls.getOperation().isEmpty()) {
208         // s.append("<div class=\"operations\">");
209         // for (Operation op : cls.getOperation()) {
210         // s.append("<div class=\"operation\">");
211         // s.append(op.getName() + "(");
212         // boolean first = true;
213         // for (OperationParameter p : op.getParameter()) {
214         // if (!first)
215         // s.append(",");
216         // s.append(p.getName());
217         // first = false;
218         // }
219         // s.append(")");
220         // s.append("</div>");
221         // }
222         // s.append("</div>");
223         // }
224         if (cls.getLifecycle() != null && !cls.getLifecycle().getEvent().isEmpty()) {
225             s.append("<div class=\"events\">");
226             for (JAXBElement<? extends Event> event : cls.getLifecycle().getEvent()) {
227                 s.append("<div class=\"event\">");
228                 s.append(event.getValue().getName());
229                 s.append("</div>");
230             }
231             s.append("</div>");
232         }
233         s.append("</div>\n");
234     }
235 
236     private BigInteger getAssociationClassRelationship(Class cls) {
237         for (JAXBElement<? extends Attribute> element : cls.getAttribute())
238             if (element.getValue() instanceof ReferentialAttribute) {
239                 ReferentialAttribute ref = (ReferentialAttribute) element.getValue();
240                 if (ref.getReference().getValue() instanceof AssociativeReference) {
241                     return ref.getReference().getValue().getRelationship();
242                 }
243             }
244         return null;
245     }
246 }