Skip to content

Commit cbae2fd

Browse files
committed
make use of Collections.synchronizedList(new ArrayList<>()) to avoid java.util.ConcurrentModificationException
1 parent 891aa05 commit cbae2fd

File tree

7 files changed

+222
-138
lines changed

7 files changed

+222
-138
lines changed

src/main/java/org/intellij/sequencer/diagram/Diagram.java

Lines changed: 124 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,26 @@
55
import java.awt.*;
66
import java.io.IOException;
77
import java.util.ArrayList;
8+
import java.util.Collections;
89
import java.util.List;
910

1011
public class Diagram {
1112
private static final Logger LOGGER = Logger.getLogger(Diagram.class);
1213

13-
private List<DisplayObject> _objectLifeLines = new ArrayList<>();
14-
private List<DisplayLink> _links = new ArrayList<>();
14+
private final List<DisplayObject> _objectLifeLines = Collections.synchronizedList(new ArrayList<>());
15+
private final List<DisplayLink> _links = Collections.synchronizedList(new ArrayList<>());
1516

1617
public Diagram() {
1718
}
1819

1920
public void build(String queryString) {
20-
_objectLifeLines = new ArrayList<>();
21-
_links = new ArrayList<>();
21+
_objectLifeLines.clear();
22+
_links.clear();
2223

2324
Parser p = new Parser();
2425
try {
2526
p.parse(queryString);
26-
} catch(IOException ioe) {
27+
} catch (IOException ioe) {
2728
LOGGER.error("IOException", ioe);
2829
return;
2930
}
@@ -35,40 +36,44 @@ public void build(String queryString) {
3536

3637
List<Link> theDisplayLinks = p.getLinks();
3738
int seq = 0;
38-
for (Link link : theDisplayLinks) {
39-
int fromSeq = link.getFrom().getSeq();
40-
int toSeq = link.getTo().getSeq();
41-
DisplayObject fromObj = _objectLifeLines.get(fromSeq);
42-
DisplayObject toObj = _objectLifeLines.get(toSeq);
43-
DisplayLink displayLink = null;
44-
if (link instanceof Call) {
45-
if (fromSeq == toSeq)
46-
displayLink = new DisplaySelfCall(link, fromObj, toObj, seq);
47-
else
48-
displayLink = new DisplayCall(link, fromObj, toObj, seq);
49-
} else if (link instanceof CallReturn) {
50-
if (fromSeq == toSeq)
51-
displayLink = new DisplaySelfCallReturn(link, fromObj, toObj, seq);
52-
else
53-
displayLink = new DisplayCallReturn(link, fromObj, toObj, seq);
54-
} else {
55-
LOGGER.error("Unknown link: " + link);
56-
}
57-
if (displayLink != null) {
58-
_links.add(displayLink);
59-
++seq;
39+
synchronized (_objectLifeLines) {
40+
for (Link link : theDisplayLinks) {
41+
int fromSeq = link.getFrom().getSeq();
42+
int toSeq = link.getTo().getSeq();
43+
DisplayObject fromObj = _objectLifeLines.get(fromSeq);
44+
DisplayObject toObj = _objectLifeLines.get(toSeq);
45+
DisplayLink displayLink = null;
46+
if (link instanceof Call) {
47+
if (fromSeq == toSeq)
48+
displayLink = new DisplaySelfCall(link, fromObj, toObj, seq);
49+
else
50+
displayLink = new DisplayCall(link, fromObj, toObj, seq);
51+
} else if (link instanceof CallReturn) {
52+
if (fromSeq == toSeq)
53+
displayLink = new DisplaySelfCallReturn(link, fromObj, toObj, seq);
54+
else
55+
displayLink = new DisplayCallReturn(link, fromObj, toObj, seq);
56+
} else {
57+
LOGGER.error("Unknown link: " + link);
58+
}
59+
if (displayLink != null) {
60+
_links.add(displayLink);
61+
++seq;
62+
}
6063
}
6164
}
6265

63-
for (ObjectInfo info : theObjects) {
64-
DisplayObject displayInfo = _objectLifeLines.get(info.getSeq());
65-
for (MethodInfo methodInfo : info.getMethods()) {
66-
int startSeq = methodInfo.getStartSeq();
67-
int endSeq = methodInfo.getEndSeq();
68-
if ((startSeq < _links.size()) && (endSeq < _links.size())) {
69-
DisplayMethod methodBox = new DisplayMethod(info, methodInfo,
70-
_links.get(startSeq), _links.get(endSeq));
71-
displayInfo.addMethod(methodBox);
66+
synchronized (_objectLifeLines) {
67+
for (ObjectInfo info : theObjects) {
68+
DisplayObject displayInfo = _objectLifeLines.get(info.getSeq());
69+
for (MethodInfo methodInfo : info.getMethods()) {
70+
int startSeq = methodInfo.getStartSeq();
71+
int endSeq = methodInfo.getEndSeq();
72+
if ((startSeq < _links.size()) && (endSeq < _links.size())) {
73+
DisplayMethod methodBox = new DisplayMethod(info, methodInfo,
74+
_links.get(startSeq), _links.get(endSeq));
75+
displayInfo.addMethod(methodBox);
76+
}
7277
}
7378
}
7479
}
@@ -85,111 +90,127 @@ public Dimension layoutObjects(Graphics2D g2, int inset) {
8590
}
8691

8792
int maxX = 200;
88-
for(int i = 0; i < _objectLifeLines.size(); ++i) {
89-
DisplayObject obj = _objectLifeLines.get(i);
90-
if(LOGGER.isDebugEnabled())
91-
LOGGER.debug("Laying out " + obj);
92-
for (DisplayLink call : obj.getCalls()) {
93-
int availableGap;
94-
if (call.isSelfCall()) {
95-
if (i == _objectLifeLines.size() - 1) {
96-
int width = obj.getWidth();
97-
if (width < call.getTextWidth())
98-
obj.setWidth(obj.getTextWidth() + call.getTextWidth());
99-
continue;
93+
synchronized (_objectLifeLines) {
94+
for (int i = 0; i < _objectLifeLines.size(); ++i) {
95+
DisplayObject obj = _objectLifeLines.get(i);
96+
if (LOGGER.isDebugEnabled())
97+
LOGGER.debug("Laying out " + obj);
98+
for (DisplayLink call : obj.getCalls()) {
99+
int availableGap;
100+
if (call.isSelfCall()) {
101+
if (i == _objectLifeLines.size() - 1) {
102+
int width = obj.getWidth();
103+
if (width < call.getTextWidth())
104+
obj.setWidth(obj.getTextWidth() + call.getTextWidth());
105+
continue;
106+
} else {
107+
availableGap = obj.calcCurrentGap(
108+
_objectLifeLines.get(i + 1), call.getSeq());
109+
}
100110
} else {
101-
availableGap = obj.calcCurrentGap(
102-
_objectLifeLines.get(i + 1), call.getSeq());
111+
availableGap = obj.calcCurrentGap(call.getTo(), call.getSeq());
103112
}
104-
} else {
105-
availableGap = obj.calcCurrentGap(call.getTo(), call.getSeq());
106-
}
107113

108-
if (availableGap < call.getTextWidth()) {
109-
int offset = call.getTextWidth() - availableGap;
110-
if (LOGGER.isDebugEnabled())
111-
LOGGER.debug("gap too small by " + offset);
112-
int startJ = i + 1;
113-
if (call.getTo().getSeq() < startJ)
114-
startJ = call.getTo().getSeq() + 1;
115-
for (int j = startJ; j < _objectLifeLines.size(); ++j) {
116-
(_objectLifeLines.get(j)).translate(offset);
114+
if (availableGap < call.getTextWidth()) {
115+
int offset = call.getTextWidth() - availableGap;
116+
if (LOGGER.isDebugEnabled())
117+
LOGGER.debug("gap too small by " + offset);
118+
int startJ = i + 1;
119+
if (call.getTo().getSeq() < startJ)
120+
startJ = call.getTo().getSeq() + 1;
121+
for (int j = startJ; j < _objectLifeLines.size(); ++j) {
122+
(_objectLifeLines.get(j)).translate(offset);
123+
}
117124
}
118125
}
126+
maxX = obj.getX() + 2 * obj.getWidth() + inset;
119127
}
120-
maxX = obj.getX() + 2 * obj.getWidth() + inset;
121-
}
122128

123-
if(_objectLifeLines.isEmpty())
124-
y = 100;
125-
else
126-
y += (_objectLifeLines.get(0)).getHeight();
127-
for (DisplayLink link : _links) {
128-
link.setY(y);
129-
link.initTwo();
130-
y += link.getTextHeight() + link.getLinkHeight();
129+
if (_objectLifeLines.isEmpty())
130+
y = 100;
131+
else
132+
y += (_objectLifeLines.get(0)).getHeight();
133+
}
134+
synchronized (_links) {
135+
for (DisplayLink link : _links) {
136+
link.setY(y);
137+
link.initTwo();
138+
y += link.getTextHeight() + link.getLinkHeight();
139+
}
131140
}
132141
y += 10;
133142
calculateFullSize(y);
134143
return new Dimension(maxX, y);
135144
}
136145

137146
private void calculateFullSize(int height) {
138-
for(int i = 0; i < _objectLifeLines.size(); i++) {
139-
DisplayObject displayObject = _objectLifeLines.get(i);
140-
displayObject.setFullHeight(height);
141-
if(i + 1 == _objectLifeLines.size())
142-
displayObject.setFullWidth(displayObject.getWidth());
143-
else {
144-
DisplayObject nextDisplayObject = _objectLifeLines.get(i + 1);
145-
displayObject.setFullWidth(nextDisplayObject.getCenterX() - displayObject.getX());
147+
synchronized (_objectLifeLines) {
148+
for (int i = 0; i < _objectLifeLines.size(); i++) {
149+
DisplayObject displayObject = _objectLifeLines.get(i);
150+
displayObject.setFullHeight(height);
151+
if (i + 1 == _objectLifeLines.size())
152+
displayObject.setFullWidth(displayObject.getWidth());
153+
else {
154+
DisplayObject nextDisplayObject = _objectLifeLines.get(i + 1);
155+
displayObject.setFullWidth(nextDisplayObject.getCenterX() - displayObject.getX());
156+
}
146157
}
147158
}
148159
}
149160

150161
public Dimension getPreferredHeaderSize() {
151162
int maxHeight = 0, width = 0;
152-
for (DisplayObject displayObjectInfo : _objectLifeLines) {
153-
int preferredHeight = displayObjectInfo.getPreferredHeaderHeight();
154-
if (maxHeight < preferredHeight)
155-
maxHeight = preferredHeight;
156-
width += displayObjectInfo.getPreferredHeaderWidth();
163+
synchronized (_objectLifeLines) {
164+
for (DisplayObject displayObjectInfo : _objectLifeLines) {
165+
int preferredHeight = displayObjectInfo.getPreferredHeaderHeight();
166+
if (maxHeight < preferredHeight)
167+
maxHeight = preferredHeight;
168+
width += displayObjectInfo.getPreferredHeaderWidth();
169+
}
157170
}
158171
return new Dimension(width, maxHeight);
159172
}
160173

161174
public ScreenObject findScreenObjectByXY(int x, int y) {
162175
DisplayMethod selectedMethodBox = null;
163-
for (DisplayObject displayObject : _objectLifeLines) {
164-
if (displayObject.isInRange(x, y))
165-
return displayObject;
166-
DisplayMethod methodBox = displayObject.findMethod(x, y);
167-
if (methodBox != null) {
168-
if (selectedMethodBox == null || selectedMethodBox.getX() < methodBox.getX()) {
169-
selectedMethodBox = methodBox;
176+
synchronized (_objectLifeLines) {
177+
for (DisplayObject displayObject : _objectLifeLines) {
178+
if (displayObject.isInRange(x, y))
179+
return displayObject;
180+
DisplayMethod methodBox = displayObject.findMethod(x, y);
181+
if (methodBox != null) {
182+
if (selectedMethodBox == null || selectedMethodBox.getX() < methodBox.getX()) {
183+
selectedMethodBox = methodBox;
184+
}
170185
}
171186
}
172187
}
173-
if(selectedMethodBox == null) {
174-
for (DisplayLink displayLink : _links) {
175-
if (displayLink.isReturnLink())
176-
continue;
177-
if (displayLink.isInRange(x, y))
178-
return displayLink;
188+
if (selectedMethodBox == null) {
189+
synchronized (_links) {
190+
for (DisplayLink displayLink : _links) {
191+
if (displayLink.isReturnLink())
192+
continue;
193+
if (displayLink.isInRange(x, y))
194+
return displayLink;
195+
}
179196
}
180197
}
181198
return selectedMethodBox;
182199
}
183200

184201
public void paint(Graphics2D g2) {
185-
for (DisplayObject displayObject : _objectLifeLines) {
186-
displayObject.paint(g2);
202+
synchronized (_objectLifeLines) {
203+
for (DisplayObject displayObject : _objectLifeLines) {
204+
displayObject.paint(g2);
205+
}
187206
}
188207
}
189208

190209
public void paintHeader(Graphics2D g2) {
191-
for (DisplayObject displayObject : _objectLifeLines) {
192-
displayObject.paintHeader(g2);
210+
synchronized (_objectLifeLines) {
211+
for (DisplayObject displayObject : _objectLifeLines) {
212+
displayObject.paintHeader(g2);
213+
}
193214
}
194215
}
195216

@@ -202,6 +223,6 @@ public boolean isEmpty() {
202223
}
203224

204225
public boolean nonEmpty() {
205-
return ! isEmpty();
226+
return !isEmpty();
206227
}
207228
}

0 commit comments

Comments
 (0)