package com.baselet.element.sequence_aio.facet;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.baselet.control.enums.LineType;
import com.baselet.element.sequence_aio.facet.StateInvariant.StateInvariantStyle;
/**
* Constructs a sequence diagram.
* No modifications are allowed after the diagram was returned.
* Events which affect a lifeline must be added after the affected lifelines.
*
*/
public class SequenceDiagramBuilder {
private static final Logger log = LoggerFactory.getLogger(SequenceDiagramBuilder.class);
private final String DEFAULT_ID_PREFIX = "id";
private final SequenceDiagram dia;
private final Map<Lifeline, LifelineState> currentLifelineState;
/** if true no default ids are generated and every lifeline needs an id */
private boolean overrideDefaultIds;
private final Map<String, Lifeline> ids;
private final LinkedList<ActiveCombinedFragment> activeCombinedFragmentStack;
/** ids on a lifeline for occurrenceSpecifications (message endpoint or execution specification start/end) */
private final Map<Lifeline, Map<String, OccurrenceSpecification>> lifelineLocalIds;
/** stores all warnings which are found while the sequence diagram is built */
private final List<String> warnings;
private int currentTick;
private int lastMessageReceiveTick;
private boolean diagramRetrieved;
public SequenceDiagramBuilder() {
overrideDefaultIds = false;
ids = new HashMap<String, Lifeline>();
activeCombinedFragmentStack = new LinkedList<SequenceDiagramBuilder.ActiveCombinedFragment>();
lifelineLocalIds = new HashMap<Lifeline, Map<String, OccurrenceSpecification>>();
dia = new SequenceDiagram();
currentLifelineState = new HashMap<Lifeline, SequenceDiagramBuilder.LifelineState>();
warnings = new LinkedList<String>();
currentTick = 0;
lastMessageReceiveTick = 0;
diagramRetrieved = false;
}
public void setTitle(String title) {
checkState();
dia.setTitle(title);
}
public void setText(String text) {
checkState();
dia.setText(text);
}
/**
* @param id of the lifeline which should be returned
* @return the lifeline or null if no lifeline is associated with the given id
*/
public Lifeline getLifeline(String id) {
return ids.get(id);
}
/**
* @param id of the lifeline which should be returned
* @return the lifeline
* @throws SequenceDiagramException if no lifeline is associated with the given id
*/
Lifeline getLifelineException(String id) {
if (!ids.containsKey(id)) {
throw new SequenceDiagramException("No lifeline is associated with the id: '" + id + "'");
}
return ids.get(id);
}
public Lifeline[] getLifelineInterval(String id1, String id2) {
try {
return getLifelineIntervalException(id1, id2);
} catch (SequenceDiagramException e) {
return new Lifeline[0];
}
}
public Lifeline[] getLifelineIntervalException(String id1, String id2) {
Lifeline ll1 = getLifelineException(id1);
Lifeline ll2 = getLifelineException(id2);
if (ll1.getIndex() > ll2.getIndex()) {
Lifeline tmp = ll1;
ll1 = ll2;
ll2 = tmp;
}
return Arrays.copyOfRange(dia.getLifelinesArray(), ll1.getIndex(), ll2.getIndex() + 1);
}
/**
*
* @param headText the text which is drawn in the head
* @param id can be NULL, if none of reorder and idoverride option is active
* @param headType the lifeline style
* @param createdOnStart if false the lifeline will be created by the first message sent to this lifeline
*/
public void addLiveline(String headText, String id, Lifeline.LifelineHeadType headType, boolean createdOnStart,
boolean execSpecFromStart) {
checkState();
if (isOverrideDefaultIds() && id == null) {
throw new SequenceDiagramException("If the override option is set to true then every lifeline needs an id!");
}
Lifeline newLifeline = dia.addLiveline(headText, headType, createdOnStart, execSpecFromStart);
if (id != null) {
if (ids.containsKey(id)) {
throw new SequenceDiagramException("There is already a lifeline which is associated with the id '" +id +
"', please choose another identifier.");
}
ids.put(id, newLifeline);
}
if (!overrideDefaultIds) {
if (ids.containsKey(DEFAULT_ID_PREFIX + dia.getLifelineCount())) {
throw new SequenceDiagramException("There is already a lifeline which is associated with the default id '" +
DEFAULT_ID_PREFIX + dia.getLifelineCount() +
"',\nplease choose another identifier or add the option 'overrideIds=true'.");
}
ids.put(DEFAULT_ID_PREFIX + dia.getLifelineCount(), newLifeline);
}
lifelineLocalIds.put(newLifeline, new HashMap<String, OccurrenceSpecification>());
LifelineState newLifelineState = new LifelineState();
if (execSpecFromStart && createdOnStart) {
newLifelineState.execSpecStartTickStack.addFirst(-1);
}
currentLifelineState.put(newLifeline, newLifelineState);
}
/**
*
* @param id of the lifeline
* @param event e.g. message, invariant, activity
*/
private void addLifelineOccurrence(String id, LifelineOccurrence occurrence) {
checkState();
try {
getLifelineException(id).addLifelineOccurrenceAtTick(occurrence, currentTick);
} catch (SequenceDiagramCheckedException ex) {
throw new SequenceDiagramException("Error on lifeline '" + id + "': " + ex.getMessage(), ex);
}
}
public void addTextOnLifeline(String lifelineId, String text) {
addLifelineOccurrence(lifelineId, new TextOnLifeline(text));
}
public void addStateInvariant(String lifelineId, String text, boolean drawAsState) {
addLifelineOccurrence(lifelineId, new StateInvariant(text,
drawAsState ? StateInvariantStyle.STATE : StateInvariantStyle.CURLY_BRACKETS));
}
public void addCoregion(String id, boolean start) {
checkState();
// check that every coregion should be closed and coregion should not overlap, but only add a warning and trust the user
Lifeline lifeline = getLifelineException(id);
LifelineState lifelineState = currentLifelineState.get(lifeline);
if (lifelineState.coregionActive && start) {
addWarning(id, "A new coregion was started while an old one was still active.");
}
else if (!lifelineState.coregionActive && !start) {
addWarning(id, "A coregion was closed, but no coregion was active.");
}
try {
lifeline.addLifelineOccurrenceAtTick(new Coregion(lifeline, currentTick, start), currentTick);
lifelineState.coregionActive = start;
} catch (SequenceDiagramCheckedException ex) {
throw new SequenceDiagramException("Error on lifeline '" + id + "': " + ex.getMessage(), ex);
}
}
public void destroyLifeline(String id) {
checkState();
// check that every coregion should be closed and coregion should not overlap, but only add a warning and trust the user
Lifeline lifeline = getLifelineException(id);
if (lifeline.getDestroyed() != null) {
addWarning(id, "The lifeline was already destroyed.");
}
else {
lifeline.setDestroyed(currentTick);
}
}
public void changeExecutionSpecification(String lifelineId, boolean on) {
checkState();
// check that they don't collide i.e. 2 changes at the same tick
Lifeline lifeline = getLifelineException(lifelineId);
LifelineState lifelineState = currentLifelineState.get(lifeline);
if (on) {
if (lifelineState.execSpecStartTickStack.size() > 0 && lifelineState.execSpecStartTickStack.peek() == currentTick) {
throw new SequenceDiagramException("On lifeline " + lifelineId + " two executionspecifications start at the same tick, this is not possible.");
}
if (lifelineState.lastEndOfExecSpec == currentTick) {
throw new SequenceDiagramException("On lifeline " + lifelineId + " two executionspecifications overlap, this is not possible.");
}
if (!lifeline.isCreatedOnStart() && (lifeline.getCreated() == null || lifeline.getCreated() >= currentTick)) {
throw new SequenceDiagramException("Error on lifeline '" + lifelineId + "': the lifeline can not contain executionspecifications before it is created.");
}
lifelineState.execSpecStartTickStack.addFirst(currentTick);
}
else {
if (lifelineState.execSpecStartTickStack.size() == 0) {
throw new SequenceDiagramException("On lifeline " + lifelineId + " a executionspecification was closed but no active executionspecification exists.");
}
int startTick = lifelineState.execSpecStartTickStack.poll();
if (startTick == currentTick) {
throw new SequenceDiagramException("On lifeline " + lifelineId + " a executionspecification was closed too soon, every executionspecification needs to be at least 1 tick long.");
}
if (lifelineState.lastEndOfExecSpec == currentTick) {
throw new SequenceDiagramException("On lifeline " + lifelineId + " two executionspecifications end at the same tick, this is not possible.");
}
lifelineState.lastEndOfExecSpec = currentTick;
lifeline.addExecutionSpecification(new ExecutionSpecification(startTick, currentTick));
}
}
/**
* @param fromId
* @param toId
* @param duration
* @param text
* @param lineType
* @param arrowType
* @param fromLocalId can be null, if not null the send end point will be associated with the given id
* @param toLocalId can be null, if not null the receive end point will be associated with the given id
*/
public void addMessage(String fromId, String toId, int duration, String text, LineType lineType,
Message.ArrowType arrowType, String fromLocalId, String toLocalId) {
checkState();
// check that a self message has a duration > 0
if (fromId.equals(toId)) {
if (duration < 1) {
throw new SequenceDiagramException("The duration of a self message must be greater than 0, but was " + duration + ".");
}
}
lastMessageReceiveTick = Math.max(lastMessageReceiveTick, currentTick + duration);
Lifeline from = getLifelineException(fromId);
checkLifelineSendMessage(from, fromId);
Lifeline to = getLifelineException(toId);
// check if the message doesn't end before the lifeline was created
if (!to.isCreatedOnStart() && to.getCreated() != null && currentTick + duration <= to.getCreated()) {
throw new SequenceDiagramException("A message can't end on a lifeline before this lifeline was created.\n" +
"Please increase the messages duration by at least " + (to.getCreated() + 1 - (currentTick + duration)) + ".");
}
else if (currentTick + duration < 0) {
throw new SequenceDiagramException("A message can't end on a lifeline before this lifeline was created.\n" +
"Please increase the messages duration by at least " + -(currentTick + duration) + ".");
}
if (!to.isCreatedOnStart() && to.getCreated() == null) {
to.setCreated(currentTick + duration);
if (to.isExecSpecFromStart()) {
currentLifelineState.get(to).execSpecStartTickStack.push(currentTick + duration);
}
}
Message msg = new Message(from, to, duration, currentTick, text, arrowType, lineType);
if (fromLocalId != null) {
addOccurrenceSpecification(from, fromId, fromLocalId, msg.sendOccurrenceSpecification());
}
if (toLocalId != null) {
addOccurrenceSpecification(to, toId, toLocalId, msg.receiveOccurrenceSpecification());
}
dia.addLifelineSpanningTickSpanningOccurrence(msg);
}
public void addLostMessage(String fromId, String text, LineType lineType, Message.ArrowType arrowType, String fromLocalId) {
checkState();
Lifeline from = getLifelineException(fromId);
checkLifelineSendMessage(from, fromId);
LostOrFoundMessage msg = new LostOrFoundMessage(from, false, currentTick, text, arrowType, lineType);
if (fromLocalId != null) {
addOccurrenceSpecification(from, fromId, fromLocalId, msg.sendOccurrenceSpecification());
}
addLifelineOccurrence(fromId, msg);
}
public void addFoundMessage(String toId, String text, LineType lineType, Message.ArrowType arrowType, String toLocalId) {
checkState();
Lifeline to = getLifelineException(toId);
if (!to.isCreatedOnStart()) {
if (to.getCreated() == null || to.getCreated() >= currentTick) {
throw new SequenceDiagramException("The lifeline " +toId +
" was not yet created, therefore it is not possible to send a found message to it.");
}
}
LostOrFoundMessage msg = new LostOrFoundMessage(to, true, currentTick, text, arrowType, lineType);
if (toLocalId != null) {
addOccurrenceSpecification(to, toId, toLocalId, msg.receiveOccurrenceSpecification());
}
addLifelineOccurrence(toId, msg);
}
public void addReceiveGateMessage(String fromId, String text, LineType lineType, Message.ArrowType arrowType, String fromLocalId) {
checkState();
Lifeline from = getLifelineException(fromId);
checkLifelineSendMessage(from, fromId);
GateMessage msg = GateMessage.createReceiveGateMessage(from, currentTick, text, arrowType, lineType,
dia.getLifelinesArray()[0], dia.getLifelinesArray()[dia.getLifelinesArray().length - 1]);
if (fromLocalId != null) {
addOccurrenceSpecification(from, fromId, fromLocalId, msg.sendOccurrenceSpecification());
}
dia.addLifelineSpanningTickSpanningOccurrence(msg);
}
public void addSendGateMessage(String toId, String text, LineType lineType, Message.ArrowType arrowType, String toLocalId) {
checkState();
Lifeline to = getLifelineException(toId);
GateMessage msg = GateMessage.createSendGateMessage(to, currentTick, text, arrowType, lineType,
dia.getLifelinesArray()[0], dia.getLifelinesArray()[dia.getLifelinesArray().length - 1]);
if (toLocalId != null) {
addOccurrenceSpecification(to, toId, toLocalId, msg.receiveOccurrenceSpecification());
}
if (!to.isCreatedOnStart() && to.getCreated() == null) {
to.setCreated(currentTick);
}
dia.addLifelineSpanningTickSpanningOccurrence(msg);
}
private void checkLifelineSendMessage(Lifeline from, String id) {
if (!from.isCreatedOnStart()) {
if (from.getCreated() == null || from.getCreated() >= currentTick) {
throw new SequenceDiagramException("The lifeline " + id + " was not yet created, therefore it is not possible to send a message from it.");
}
}
}
public void addGeneralOrdering(String earlierLifelineId, String earlierLifelineLocalId,
String laterLifelineId, String laterLifelineLocalId) {
checkState();
dia.addLifelineSpanningTickSpanningOccurrence(new GeneralOrdering(
getLifelineOccurrenceSpecException(earlierLifelineId, earlierLifelineLocalId),
getLifelineOccurrenceSpecException(laterLifelineId, laterLifelineLocalId),
getLifelineIntervalException(earlierLifelineId, laterLifelineId)));
}
// private void addOccurrenceSpecification(String lifelineId, String localId, OccurrenceSpecification occurrence) {
// addOccurrenceSpecification(getLifelineException(lifelineId), lifelineId, localId, occurrence);
// }
private void addOccurrenceSpecification(Lifeline lifeline, String lifelineId, String localId, OccurrenceSpecification occurrence) {
if (lifelineLocalIds.get(lifeline).containsKey(localId)) {
throw new SequenceDiagramException("The lifeline '" + lifelineId + "' has already a local id '" + localId + "', please choose another id.");
}
lifelineLocalIds.get(lifeline).put(localId, occurrence);
}
private OccurrenceSpecification getLifelineOccurrenceSpecException(String lifelineId, String localId) {
Lifeline llifeline = getLifelineException(lifelineId);
OccurrenceSpecification occurrenceSpec = lifelineLocalIds.get(llifeline).get(localId);
if (occurrenceSpec == null) {
throw new SequenceDiagramException("No lifeline occurrence with the id '" + localId + "' could be found on lifeline '" + lifelineId + "'.");
}
return occurrenceSpec;
}
public void addInteractionUse(String startId, String endId, String text) {
checkState();
Lifeline[] lifelines = getLifelineIntervalException(startId, endId);
dia.addLifelineSpanningTickSpanningOccurrence(new InteractionUse(currentTick, text, lifelines));
}
public void addContinuation(String startId, String endId, String text) {
checkState();
Lifeline[] lifelines = getLifelineIntervalException(startId, endId);
dia.addLifelineSpanningTickSpanningOccurrence(new Continuation(currentTick, text, lifelines));
}
/**
* @param startId starting lifeline
* @param endId ending lifeline
* @param cfId the id of the combined Fragment, can be null
* @param operator of the combined fragment
*/
public void beginCombinedFragment(String startId, String endId, String cfId, String operator) {
checkState();
Lifeline[] lifelines;
if (startId == null && endId == null) {
lifelines = Arrays.<Lifeline> copyOf(dia.getLifelinesArray(), dia.getLifelinesArray().length);
}
else {
lifelines = getLifelineIntervalException(startId, endId);
}
activeCombinedFragmentStack.push(new ActiveCombinedFragment(new CombinedFragment(lifelines, currentTick, operator), cfId));
activeCombinedFragmentStack.peek().activeOperand = new ActiveOperand(currentTick);
}
/**
* @param cfId can be null, then the latest created combined fragment which was not closed is closed.
* Otherwise the combined fragment associated with the given id is closed.
*/
public void endCombinedFragment(String cfId) {
checkState();
if (activeCombinedFragmentStack.size() == 0) {
throw new SequenceDiagramException("Error a combined fragment was closed, but no open one exists.");
}
ActiveCombinedFragment currentCombFrag = null;
if (cfId == null) {
currentCombFrag = activeCombinedFragmentStack.pop();
}
else {
ListIterator<ActiveCombinedFragment> activeCFIter = activeCombinedFragmentStack.listIterator();
while (activeCFIter.hasNext()) {
currentCombFrag = activeCFIter.next();
if (cfId.equals(currentCombFrag.id)) {
activeCFIter.remove();
break;
}
currentCombFrag = null;
}
}
if (currentCombFrag == null) {
throw new SequenceDiagramException("Error no combined fragment with id '" + cfId + "' was found.");
}
else {
// TODO operand rewrite
// if (currentCombFrag.activeOperand != null) {
// throw new SequenceDiagramException("Error a combined fragment was closed, but there is still an open operand present.");
// }
currentCombFrag.combFrag.addOperand(currentCombFrag.activeOperand.startTick, currentTick);
dia.addLifelineSpanningTickSpanningOccurrence(currentCombFrag.combFrag);
}
}
public void endAndBeginOperand(String cfId) {
checkState();
if (activeCombinedFragmentStack.size() == 0) {
throw new SequenceDiagramException("Error a combined fragment was closed, but no open one exists.");
}
ActiveCombinedFragment currentCombFrag = null;
if (cfId == null) {
currentCombFrag = activeCombinedFragmentStack.peek();
}
else {
ListIterator<ActiveCombinedFragment> activeCFIter = activeCombinedFragmentStack.listIterator();
while (activeCFIter.hasNext()) {
currentCombFrag = activeCFIter.next();
if (cfId.equals(currentCombFrag.id)) {
break;
}
currentCombFrag = null;
}
}
if (currentCombFrag == null) {
throw new SequenceDiagramException("Error no combined fragment with id '" + cfId + "' was found.");
}
else {
// TODO operand rewrite
currentCombFrag.combFrag.addOperand(currentCombFrag.activeOperand.startTick, currentTick);
currentCombFrag.activeOperand = new ActiveOperand(currentTick);
}
}
// public void beginOperand() {
// checkState();
// beginOperand(null, "");
// }
/**
*
* @param text if empty or null no constraint will be generated
* @param lifelineId if empty or null the first occurrence in the operand will determine the lifeline on which the constraint is placed
*/
// public void beginOperand(String text, String lifelineId) {
// checkState();
// if (activeCombinedFragmentStack.size() == 0) {
// throw new SequenceDiagramException("Error an operand must lie in a combined fragment, but no open one exists.");
// }
// ActiveCombinedFragment currentCombFrag = activeCombinedFragmentStack.peek();
// if (currentCombFrag.activeOperand != null) {
// throw new SequenceDiagramException("Error a new operand was started, but there is still an open operand present.");
// }
// ActiveOperand operand;
// if (text == null || text.isEmpty()) {
// operand = new ActiveOperand(currentTick);
// }
// else {
// operand = new ActiveOperand(text, getLifeline(lifelineId), currentTick);
// }
// currentCombFrag.activeOperand = operand;
// }
// public void endOperand() {
// checkState();
// if (activeCombinedFragmentStack.size() == 0) {
// throw new SequenceDiagramException("Error an operand must lie in a combined fragment, but no open one exists.");
// }
// ActiveCombinedFragment currentCombFrag = activeCombinedFragmentStack.peek();
// if (currentCombFrag.activeOperand == null) {
// throw new SequenceDiagramException("Error a operand was closed, but there is no open operand.");
// }
// ActiveOperand operand = currentCombFrag.activeOperand;
// currentCombFrag.activeOperand = null;
// if (operand.constraint == null) {
// currentCombFrag.combFrag.addOperand(operand.startTick, currentTick);
// }
// else {
// Lifeline lifeline = operand.assoicatedLifeline;
// if (lifeline == null) { // if it wasn't set place it on the first lifeline of the combined fragment
// lifeline = currentCombFrag.combFrag.getFirstLifeline();
// }
// try {
// currentCombFrag.combFrag.addOperand(operand.startTick, currentTick, operand.constraint, lifeline);
// } catch (SequenceDiagramCheckedException e) {
// throw new SequenceDiagramException("Error while placing the interaction '" + operand.constraint
// + "' constraint on the " + (lifeline.getIndex() + 1)
// + " lifeline from the left.\n" + e.getMessage(), e);
// }
// }
// }
/**
* advances a step down
*/
public void tick() {
tick(1);
}
/**
*
* @param tickCount needs to be > 0
*/
public void tick(int tickCount) {
checkState();
if (tickCount < 1) {
throw new IllegalArgumentException("The tickCount must be greater than 0.");
}
currentTick += tickCount;
}
public void setOverrideDefaultIds(boolean overrideDefaultIds) {
checkState();
if (dia.getLifelineCount() > 0) {
throw new SequenceDiagramException("The override ids option must be specified before any lifeline is specified.");
}
else {
this.overrideDefaultIds = overrideDefaultIds;
}
}
public boolean isOverrideDefaultIds() {
return overrideDefaultIds;
}
/**
* Should be called after the diagram is generated, because this last step can add further warnings.
* @return the empty string if no warnings exists, otherwise a headline and the warnings (with \n as line delimiter) are returned
*/
public String getWarnings() {
if (warnings.size() == 0) {
return "";
}
else {
StringBuffer strBuffer = new StringBuffer();
strBuffer.append("Warnings:");
for (String w : warnings) {
strBuffer.append('\n');
strBuffer.append(w);
}
return strBuffer.toString();
}
}
/**
* Called as final step.
* Can be called multiple times, but every time the same diagram (same reference) is returned.
* If there exists a major issue with the diagram an exception is thrown, otherwise the diagram is returned
* and if there are minor issues these are added to the warnings.
*
* @return the generated diagram
* @throws SequenceDiagramException if the diagram could not be generated.
* @see #getWarnings()
*/
public SequenceDiagram generateDiagram() {
if (diagramRetrieved) {
return dia;
}
else {
// if a created later lifeline has no message it is draw at the start and a warning is added
boolean createdLaterWarning = false;
for (Lifeline ll : dia.getLifelines()) {
if (!ll.isCreatedOnStart() && ll.getCreated() == null) {
createdLaterWarning = true;
ll.setCreatedOnStart(true);
}
}
if (createdLaterWarning) {
warnings.add("At least one lifeline was specified as created later, but didn't receive a message");
}
// TODO for each operand condition add a LL occurence to the lifeline with the first message (or to the lowest index)
// close all execution specifications and add a warning.
boolean openExecSpecs;
boolean foundOpenExecSpecs = false;
do {
openExecSpecs = false;
for (Map.Entry<Lifeline, LifelineState> e : currentLifelineState.entrySet()) {
if (e.getValue().execSpecStartTickStack.size() > 0) {
if (e.getValue().lastEndOfExecSpec < currentTick) {
e.getValue().lastEndOfExecSpec = currentTick;
e.getKey().addExecutionSpecification(
new ExecutionSpecification(e.getValue().execSpecStartTickStack.pop(), currentTick));
openExecSpecs = openExecSpecs || e.getValue().execSpecStartTickStack.size() > 0;
foundOpenExecSpecs = true;
}
}
}
if (openExecSpecs) {
currentTick++;
}
} while (openExecSpecs);
if (foundOpenExecSpecs) {
warnings.add("At least one executionspecification was not closed, any open executionspecification was closed at the end of the diagram.");
}
dia.setLastTick(Math.max(currentTick, lastMessageReceiveTick));
diagramRetrieved = true;
return dia;
}
}
/**
* throws an exception if the diagram was already returned
*/
private void checkState() {
if (diagramRetrieved) {
throw new IllegalStateException("The final diagram was returned and therefore no more changes are allowed.");
}
}
private void addWarning(String id, String text) {
warnings.add("On lifeline '" + id + "': " + text);
}
private static class LifelineState {
/** stores the last end of an execution specifications. */
int lastEndOfExecSpec = -1; // Starts at -1 since the first tick is 0 and therefore no overlap is possible
LinkedList<Integer> execSpecStartTickStack = new LinkedList<Integer>();
boolean coregionActive = false;
}
private static class ActiveCombinedFragment {
public ActiveCombinedFragment(CombinedFragment combFrag, String cfId) {
super();
this.combFrag = combFrag;
id = cfId;
}
String id;
CombinedFragment combFrag;
ActiveOperand activeOperand = null;
}
private static class ActiveOperand {
public ActiveOperand(int startTick) {
super();
this.startTick = startTick;
}
// public ActiveOperand(String constraint, Lifeline assoicatedLifeline, int startTick) {
// super();
// this.constraint = constraint;
// this.assoicatedLifeline = assoicatedLifeline;
// this.startTick = startTick;
// }
//
// String constraint = null; // if empty no constraint needed
// Lifeline assoicatedLifeline = null; // lifeline on which the constraint should be drawn
int startTick;
}
}