Skip to content

Commit af7cf54

Browse files
authored
Merge pull request #348 from Systems-Modeling/ST6RI-529
ST6RI-529: Support inherited connectors, nested metadata, and ports with parameters.
2 parents 5000e86 + 863b8c1 commit af7cf54

22 files changed

Lines changed: 776 additions & 260 deletions
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*****************************************************************************
2+
* SysML 2 Pilot Implementation, PlantUML Visualization
3+
* Copyright (c) 2022 Mgnite Inc.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of theGNU Lesser General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*
18+
* @license LGPL-3.0-or-later <http://spdx.org/licenses/LGPL-3.0-or-later>
19+
*
20+
* Contributors:
21+
* Hisashi Miyashita, Mgnite Inc.
22+
*
23+
*****************************************************************************/
24+
25+
package org.omg.sysml.plantuml;
26+
27+
import java.util.List;
28+
29+
import org.omg.sysml.lang.sysml.Feature;
30+
import org.omg.sysml.lang.sysml.Membership;
31+
import org.omg.sysml.lang.sysml.Namespace;
32+
import org.omg.sysml.lang.sysml.Type;
33+
34+
class InheritKey {
35+
public final Type[] keys;
36+
private final boolean isDirect;
37+
38+
private static boolean isBelonging(Type typ, Feature f) {
39+
if (typ.getOwnedFeature().contains(f)) return true;
40+
if (typ.getInheritedFeature().contains(f)) return true;
41+
return false;
42+
}
43+
44+
private static boolean isBelonging(Type typ, Membership ms) {
45+
if (typ.getOwnedMembership().contains(ms)) return true;
46+
if (typ.getInheritedMembership().contains(ms)) return true;
47+
return false;
48+
}
49+
50+
@Override
51+
public int hashCode() {
52+
int code = 0;
53+
for (Type t: keys) {
54+
code ^= t.hashCode();
55+
}
56+
return code;
57+
}
58+
59+
@Override
60+
public boolean equals(Object o) {
61+
if (!(o instanceof InheritKey)) return false;
62+
InheritKey ki = (InheritKey) o;
63+
int len = keys.length;
64+
if (len != ki.keys.length) return false;
65+
for (int i = 0; i < len; i++) {
66+
if (!keys[i].equals(ki.keys[i])) return false;
67+
}
68+
return true;
69+
}
70+
71+
// where ctx is (n1, n2, ..., nk), keyType is the nearest enclosing type owning `ref' feature;
72+
private static int findKeyType(List<Namespace> ctx, Feature ref) {
73+
for (int i = ctx.size() - 1; i >=0; i--) {
74+
Namespace ns = ctx.get(i);
75+
if (!(ns instanceof Type)) continue;
76+
Type typ = (Type) ns;
77+
if (isBelonging(typ, ref)) return i;
78+
}
79+
return -1;
80+
}
81+
82+
private static int findKeyType(List<Namespace> ctx, Membership ref) {
83+
for (int i = ctx.size() - 1; i >=0; i--) {
84+
Namespace ns = ctx.get(i);
85+
if (!(ns instanceof Type)) continue;
86+
Type typ = (Type) ns;
87+
if (isBelonging(typ, ref)) return i;
88+
}
89+
return -1;
90+
}
91+
92+
private static void fill(Type[] keys, List<Namespace> ctx, List<Integer> inheritIdices, int i) {
93+
for (int k = 0; k < i; k++) {
94+
int idx = inheritIdices.get(k);
95+
// It must not cause ClassCastException
96+
Type typ = (Type) ctx.get(idx);
97+
keys[k] = typ;
98+
}
99+
}
100+
101+
private InheritKey(List<Namespace> ctx, List<Integer> inheritIdices, int i) {
102+
Type[] keys = new Type[i];
103+
fill(keys, ctx, inheritIdices, i);
104+
this.keys = keys;
105+
this.isDirect = true;
106+
}
107+
108+
private InheritKey(List<Namespace> ctx, List<Integer> inheritIdices, int i, Type tail) {
109+
Type[] keys = new Type[i + 1];
110+
fill(keys, ctx, inheritIdices, i);
111+
keys[i] = tail;
112+
this.keys = keys;
113+
this.isDirect = false;
114+
}
115+
116+
private InheritKey(Type tail) {
117+
Type[] keys = new Type[1];
118+
keys[0] = tail;
119+
this.keys = keys;
120+
this.isDirect = false;
121+
}
122+
123+
@Override
124+
public String toString() {
125+
StringBuilder sb = new StringBuilder();
126+
if (keys.length == 0) return "Empty InherityKey";
127+
sb.append("InheritKey: [");
128+
sb.append(keys[0].getName());
129+
for (int i = 1; i < keys.length; i++) {
130+
sb.append(", ");
131+
sb.append(keys[i].getName());
132+
}
133+
sb.append(']');
134+
return sb.toString();
135+
}
136+
137+
private static InheritKey constructInternal(List<Namespace> ctx, List<Integer> inheritIdices, int idx) {
138+
if (idx < 0) return null;
139+
for (int i = inheritIdices.size(); i > 0; i--) {
140+
int idx2 = inheritIdices.get(i - 1);
141+
if (idx2 == idx) {
142+
// case of [t0, t1, ..., t_idx2 == ^ow]
143+
return new InheritKey(ctx, inheritIdices, i);
144+
} else if (idx2 < idx) {
145+
// case of [t0, t1, ..., t_idx2, ^ow]
146+
Type typ = (Type) ctx.get(idx);
147+
return new InheritKey(ctx, inheritIdices, i, typ);
148+
}
149+
}
150+
{
151+
// case of (^ow)
152+
Type typ = (Type) ctx.get(idx);
153+
return new InheritKey(typ);
154+
}
155+
}
156+
157+
public static InheritKey construct(List<Namespace> ctx, List<Integer> inheritIdices, Feature ref) {
158+
int idx = findKeyType(ctx, ref);
159+
return constructInternal(ctx, inheritIdices, idx);
160+
}
161+
162+
public static InheritKey construct(List<Namespace> ctx, List<Integer> inheritIdices, Membership ref) {
163+
int idx = findKeyType(ctx, ref);
164+
return constructInternal(ctx, inheritIdices, idx);
165+
}
166+
167+
public static boolean match(InheritKey ik, List<Namespace> ctx, List<Integer> inheritIdices) {
168+
if (ik == null) {
169+
return inheritIdices.isEmpty();
170+
} else {
171+
int ctxSize = ctx.size();
172+
if (ctxSize == 0) {
173+
return false;
174+
}
175+
int iSize = inheritIdices.size();
176+
int kLen = ik.keys.length;
177+
int diff = kLen - iSize;
178+
if (diff < 1) return false;
179+
for (int i = 0; i < iSize; i++) {
180+
int idx = inheritIdices.get(i);
181+
Namespace ns = ctx.get(idx);
182+
if (!ik.keys[i].equals(ns)) return false;
183+
}
184+
if (diff == 0) return true;
185+
// In the case that ik is in the form of [..., ^ow]
186+
return ik.keys[kLen - 1].equals(ctx.get(ctxSize - 1));
187+
}
188+
}
189+
190+
public static boolean isDirectInherit(InheritKey ik) {
191+
if (ik == null) return false;
192+
return ik.isDirect;
193+
}
194+
}

org.omg.sysml.plantuml/src/org/omg/sysml/plantuml/PRelation.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
* SysML 2 Pilot Implementation, PlantUML Visualization
3-
* Copyright (c) 2020 Mgnite Inc.
3+
* Copyright (c) 2020-2022 Mgnite Inc.
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -27,6 +27,7 @@
2727
import org.omg.sysml.lang.sysml.Element;
2828

2929
class PRelation {
30+
public final InheritKey ik;
3031
public final Element src;
3132
public final Element dest;
3233
public final Element rel;
@@ -39,7 +40,8 @@ protected void setDescription(String desc) {
3940
this.description = desc;
4041
}
4142

42-
public PRelation(Element src, Element dest, Element rel, String description) {
43+
public PRelation(InheritKey ik, Element src, Element dest, Element rel, String description) {
44+
this.ik = ik;
4345
this.src = src;
4446
this.dest = dest;
4547
this.rel = rel;

org.omg.sysml.plantuml/src/org/omg/sysml/plantuml/SysML2PlantUMLText.java

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
* SysML 2 Pilot Implementation, PlantUML Visualization
3-
* Copyright (c) 2020 Mgnite Inc.
3+
* Copyright (c) 2020-2022 Mgnite Inc.
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -38,7 +38,10 @@
3838
import org.omg.sysml.lang.sysml.CaseDefinition;
3939
import org.omg.sysml.lang.sysml.CaseUsage;
4040
import org.omg.sysml.lang.sysml.Element;
41+
import org.omg.sysml.lang.sysml.Feature;
4142
import org.omg.sysml.lang.sysml.ItemDefinition;
43+
import org.omg.sysml.lang.sysml.Membership;
44+
import org.omg.sysml.lang.sysml.Namespace;
4245
import org.omg.sysml.lang.sysml.OccurrenceDefinition;
4346
import org.omg.sysml.lang.sysml.OccurrenceUsage;
4447
import org.omg.sysml.lang.sysml.PortDefinition;
@@ -395,17 +398,19 @@ public String sysML2PUML(List<? extends EObject> eObjs) {
395398

396399
addStyleHeader(sb);
397400

398-
initIdMap();
401+
init();
399402

400403
for (EObject eObj : eObjs) {
401404
if (eObj instanceof Element) {
402405
Element e = (Element) eObj;
403406
vpath.visit(e);
404407
}
405408
}
409+
vpath.init();
406410
for (EObject eObj : eObjs) {
407411
if (eObj instanceof Element) {
408412
Element e = (Element) eObj;
413+
setInherited(false);
409414
v.visit(e);
410415
}
411416
}
@@ -422,6 +427,7 @@ VPath getVPath() {
422427
private int idCounter;
423428
private IDMap idMap;
424429

430+
// element 1<-* id 1<-* path(feature, featureChain, featureChainExpression, ItemFlowEnd)
425431
private class IDMap {
426432
private final Map<Element, Integer> idMap = new HashMap<Element, Integer>();
427433
private final IDMap prev;
@@ -482,11 +488,6 @@ private IDMap(IDMap prev) {
482488
}
483489
}
484490

485-
private void initIdMap() {
486-
idCounter = 1;
487-
this.idMap = new IDMap();
488-
}
489-
490491
boolean checkId(Element e) {
491492
return idMap.checkId(e);
492493
}
@@ -508,12 +509,53 @@ Integer getId(Element e) {
508509
}
509510

510511
private boolean inherited;
511-
512512
void setInherited(boolean flag) {
513513
this.inherited = flag;
514514
}
515-
516515
boolean isInherited() {
517516
return inherited;
518517
}
518+
519+
private void init() {
520+
idCounter = 1;
521+
this.idMap = new IDMap();
522+
this.namespaces = new ArrayList<>();
523+
this.inheritingIdices = new ArrayList<>();
524+
}
525+
526+
private List<Namespace> namespaces;
527+
private List<Integer> inheritingIdices;
528+
529+
530+
void pushNamespace(Namespace ns) {
531+
namespaces.add(ns);
532+
}
533+
534+
void inheriting() {
535+
inheritingIdices.add(namespaces.size() - 1);
536+
}
537+
538+
void popNamespace() {
539+
int idx = namespaces.size() - 1;
540+
namespaces.remove(idx);
541+
int sizeI = inheritingIdices.size();
542+
if (sizeI == 0) return;
543+
sizeI--;
544+
int idxI = inheritingIdices.get(sizeI);
545+
if (idxI == idx) {
546+
inheritingIdices.remove(sizeI);
547+
}
548+
}
549+
550+
InheritKey makeInheritKey(Feature ref) {
551+
return InheritKey.construct(namespaces, inheritingIdices, ref);
552+
}
553+
554+
InheritKey makeInheritKey(Membership ref) {
555+
return InheritKey.construct(namespaces, inheritingIdices, ref);
556+
}
557+
558+
boolean matchCurrentInheritings(InheritKey ik) {
559+
return InheritKey.match(ik, namespaces, inheritingIdices);
560+
}
519561
}

org.omg.sysml.plantuml/src/org/omg/sysml/plantuml/VActionMembers.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
public class VActionMembers extends VBehavior {
3737

3838
private void addNode(Feature f, String type) {
39-
String name = getNameAnyway(f, true);
39+
String name = getNameAnyway(f);
4040
append(type);
4141
append(' ');
4242
addNameWithId(f, name, true);

org.omg.sysml.plantuml/src/org/omg/sysml/plantuml/VBehavior.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
* SysML 2 Pilot Implementation, PlantUML Visualization
3-
* Copyright (c) 2020 Mgnite Inc.
3+
* Copyright (c) 2020-2022 Mgnite Inc.
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -90,7 +90,7 @@ public String caseSuccession(Succession su) {
9090
}
9191
if ((src == null) && (dest == null)) continue;
9292
if ((src == null) || (dest == null)) {
93-
addEntryExitTransitions(new PRelation(src, dest, su, null));
93+
addEntryExitTransitions(new PRelation(makeInheritKey(su), src, dest, su, null));
9494
} else {
9595
addPRelation(src, dest, su);
9696
}
@@ -139,7 +139,7 @@ private boolean addSendAcceptActionUsage(ActionUsage au, boolean send) {
139139
}
140140
}
141141
if (text.length() == 0) {
142-
String name = getNameAnyway(au, true);
142+
String name = getNameAnyway(au);
143143
text.append(name);
144144
}
145145
addPUMLLine(au, send ? "send " : "accept ", text.toString());
@@ -267,7 +267,7 @@ public String caseTransitionUsage(TransitionUsage tu) {
267267
if (isDoneAction(tgt)) tgt = null;
268268
}
269269
if ((src == null) || (tgt == null)) {
270-
addEntryExitTransitions(new PRelation(src, tgt, tu, description));
270+
addEntryExitTransitions(new PRelation(makeInheritKey(tu), src, tgt, tu, description));
271271
} else {
272272
addPRelation(src, tgt, tu, description);
273273
}

0 commit comments

Comments
 (0)