/* * Copyright (c) 2009 Borland Software Corporation * * 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: * Michael Golubev (Borland) */ package org.eclipse.uml2.diagram.sequence.anchor; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.osgi.util.NLS; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.HorizontalConstraint; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.LifeLine; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.LifeLineElement; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.LifeLineIterator; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.OrderingConstraint; import org.eclipse.uml2.diagram.sequence.internal.missed.EmptyEnumeration; import org.eclipse.uml2.diagram.sequence.internal.missed.MissedMethods; import org.eclipse.uml2.diagram.sequence.model.edit.SDAnchor; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDBracket; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDBracketContainer; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDEntity; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDExecution; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDFrame; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDInvocation; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDLifeLine; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDLifeLineElement; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDModel; import org.eclipse.uml2.diagram.sequence.model.sequenced.SDMountingRegion; public class AnchorProcessorInput { /** * @param ignoreBrackets * allow to list brackets, which should not be included in Input model. */ public AnchorProcessorInput(SDModel interactionEntity, Set<SDBracket> ignoreBrackets) { this(interactionEntity, ignoreBrackets, ourNullFactory); } public AnchorProcessorInput(SDModel interactionEntity, Set<SDBracket> ignoreBrackets, LayoutPropertiesFactory layoutPropertiesFactory) { //long time = System.currentTimeMillis(); myLifelinesEntities = new ArrayList<SDLifeLine>(interactionEntity.getLifelines()); FillInputSession fillInputSession; try { fillInputSession = new FillInputSession(myLifelinesEntities, ignoreBrackets, layoutPropertiesFactory); } catch (RuntimeException e) { throw new SDModelUtil.ModelProblemException("Failed to build AnchorProcessorInput, something wrong with interaction", e); } myLifelines = fillInputSession.getResultLifelines(); myCreationDestructionSatisfyConditions = fillInputSession.createCreationDestructionSatisfyCondition(); myLifelineCreationTops = fillInputSession.getLifelineCreationTops(); myLifelineDestructionBottoms = fillInputSession.getLifelineDestructionBottoms(); myLifelineEntity2Index = new HashMap<SDLifeLine, Integer>(myLifelines.size()); for (int i = 0; i < myLifelinesEntities.size(); i++) { SDLifeLine lifelineEntity = myLifelinesEntities.get(i); Object res = myLifelineEntity2Index.put(lifelineEntity, new Integer(i)); if (res != null) { throw new RuntimeException("One lifeline is listed twice"); } } myIgnoredElements = ignoreBrackets; //new Exception("created, took "+(System.currentTimeMillis()-time)+"ms").printStackTrace(System.out); } public List<SDLifeLine> getLifeLinesEntities() { return myLifelinesEntities; } public List<LifeLine> lifeLinesList() { return myLifelines; } public LifelineSatisfyCondition[] getCreationDestructionSatisfyConditions() { return myCreationDestructionSatisfyConditions; } public LifelineSatisfyCondition[] getCreationDestructionSatisfyConditions(Set<SDLifeLine> essentialLifelines) { LifelineSatisfyCondition[] result = myCreationDestructionSatisfyConditions.clone(); for (int i = 0; i < result.length; i++) { if (result[i] == null) { continue; } if (!essentialLifelines.contains(getLifeLinesEntities().get(i))) { result[i] = null; } } return result; } public LifelineElementTraceable[] getLifelineCreationTops() { return myLifelineCreationTops; } public LifelineElementTraceable[] getLifelineDestructionBottoms() { return myLifelineDestructionBottoms; } public int getLifelineIndex(SDLifeLine lifelineEntity) { Integer index = (Integer) myLifelineEntity2Index.get(lifelineEntity); if (index == null) { throw new RuntimeException("Cannot find lifeline in map"); } return index.intValue(); } public LifeLineElement getLifeLineElementBeforePoint(SDAnchor createTarget) throws UnknownElementException { if (createTarget.getAnchor() == null) { LifelineImpl.BottomElement containerBottomElement = getBottomElementImpl(createTarget.getContainer()); if (createTarget.isAfterAnchor()) { return containerBottomElement.getTopElement(); } else { return containerBottomElement.getPreviousElement(); } } else { LifelineImpl.BottomElement anchorBottomElement = getBottomElementImpl(createTarget.getAnchor()); if (createTarget.isAfterAnchor()) { return anchorBottomElement; } else { return anchorBottomElement.getTopElement().getPreviousElement(); } } } boolean doesInclude(PasteRange pasteRange, SDAnchor createTarget) throws UnknownElementException { int beforeTargetPos; LifelineImpl lifelineImpl = (LifelineImpl) pasteRange.getRangeLowerElement().getLifeLine(); if (createTarget.getAnchor() == null) { LifelineImpl.BottomElement bottomElement = getBottomElementSecure(createTarget.getContainer(), lifelineImpl); if (createTarget.isAfterAnchor()) { // after begin of list beforeTargetPos = bottomElement.getTopElement().getNumber(); } else { beforeTargetPos = bottomElement.getNumber() - 1; } } else { LifelineImpl.BottomElement anchorBottomElement = getBottomElementSecure(createTarget.getAnchor(), lifelineImpl); if (createTarget.isAfterAnchor()) { // after begin of list beforeTargetPos = anchorBottomElement.getNumber(); } else { beforeTargetPos = anchorBottomElement.getTopElement().getNumber() - 1; } } LifelineImpl.BoundaryElement rangeUpperElement = (LifelineImpl.BoundaryElement) pasteRange.getRangeUpperElement(); LifelineImpl.BoundaryElement rangeLowerElement = (LifelineImpl.BoundaryElement) pasteRange.getRangeLowerElement(); return rangeUpperElement.getNumber() <= beforeTargetPos && beforeTargetPos < rangeLowerElement.getNumber(); } boolean doesInclude(PasteRange pasteRange, SDLifeLineElement entity) throws UnknownElementException { LifelineImpl.BoundaryElement upperRangeElement = (LifelineImpl.BoundaryElement) pasteRange.getRangeUpperElement(); LifelineImpl.BoundaryElement lowerRangeElement = (LifelineImpl.BoundaryElement) pasteRange.getRangeLowerElement(); LifelineImpl.BottomElement bottomEntityElement = getBottomElementSecure(entity, upperRangeElement.getLifelineImpl()); LifelineImpl.TopElement topEntityElement = bottomEntityElement.getTopElement(); return upperRangeElement.getNumber() < topEntityElement.getNumber() && lowerRangeElement.getNumber() > bottomEntityElement.getNumber(); } public SDAnchor findTargetByContainer(PasteRange pasteRange, SDBracketContainer container) { LifelineImpl.BoundaryElement upperBoundaryElement0 = (LifelineImpl.BoundaryElement) pasteRange.getRangeUpperElement(); LifelineImpl.BoundaryElement lowerBoundaryElement0 = (LifelineImpl.BoundaryElement) pasteRange.getRangeLowerElement(); LifelineImpl.BoundaryElement boundaryElement = upperBoundaryElement0; while (boundaryElement != lowerBoundaryElement0) { if (boundaryElement.isTopNotBottom()) { if (boundaryElement.getEntity() == container) { return SDAnchor.firstChildFor(container); } } else { SDLifeLineElement afterTheBottomMeansParent = boundaryElement.getEntityAfterElement(); if (afterTheBottomMeansParent == container) { return new SDAnchor(container, (SDBracket)boundaryElement.getEntity(), true); } } boundaryElement = boundaryElement.getNextBoundaryElement(); } return null; } public LifeLineElement getLifeLineElement(SDLifeLineElement entity, boolean topNotBottom, int lifelineIndex) throws UnknownElementException { LifelineImpl.BottomElement bottomElement = getBottomElementImpl(entity); if (myLifelines.get(lifelineIndex) != bottomElement.getLifeLine()) { throw new RuntimeException("Element found, but on wrong lifeline"); } if (topNotBottom) { return bottomElement.getTopElement(); } else { return bottomElement; } } public class InEntityCondition implements LifelineSatisfyCondition { public InEntityCondition(SDLifeLineElement entity, boolean isBeforeOk, boolean isInsideOk, boolean isAfterOk) throws UnknownElementException { LifelineImpl.BottomElement bottomElement = getBottomElementImpl(entity); myLifeLine = bottomElement.getLifeLine(); final int topPos = bottomElement.getTopElement().getNumber(); final int bottomPos = bottomElement.getNumber(); if (isInsideOk) { final int topPosPlus = isBeforeOk ? topPos - 1 : topPos; final int bottomPosPlus = isAfterOk ? bottomPos + 1 : bottomPos; myNumberCondition = new NumberCondition() { boolean isSatisfied(int number) { return topPosPlus <= number && number < bottomPosPlus; } }; } else if (isBeforeOk) { if (isAfterOk) { myNumberCondition = new NumberCondition() { boolean isSatisfied(int number) { return topPos - 1 == number || number == bottomPos; } }; } else { myNumberCondition = new NumberCondition() { boolean isSatisfied(int number) { return topPos - 1 == number; } }; } } else { if (isAfterOk) { myNumberCondition = new NumberCondition() { boolean isSatisfied(int number) { return number == bottomPos; } }; } else { throw new IllegalArgumentException("All 3 flags are false"); } } } public LifeLine getLifeline() { return myLifeLine; } public boolean isSatisfied(LifelineElementTraceable beforePointElement) { LifelineImpl.BoundaryElement boundaryElement = (LifelineImpl.BoundaryElement) beforePointElement; if (boundaryElement.getLifeLine() != myLifeLine) { throw new IllegalArgumentException("Wrong lifeline"); } return myNumberCondition.isSatisfied(boundaryElement.getNumber()); } private abstract class NumberCondition { abstract boolean isSatisfied(int number); } private final LifeLine myLifeLine; private final NumberCondition myNumberCondition; } /** * @return null, if pasteRange and destinationBoundary has empty * intersection */ PasteRange getLimitedRange(PasteRange pasteRange, SDEntity destinationBoundary) { LifeLineElement upperElement = pasteRange.getRangeUpperElement(); LifeLineElement lowerElement = pasteRange.getRangeLowerElement(); LifelineImpl.BoundaryElement upperBoundaryElement0 = (LifelineImpl.BoundaryElement) upperElement; LifelineImpl.BoundaryElement lowerBoundaryElement0 = (LifelineImpl.BoundaryElement) lowerElement; LifelineImpl.BoundaryElement upperBoundaryElement; LifelineImpl.BoundaryElement lowerBoundaryElement; if (destinationBoundary == null) { upperBoundaryElement = upperBoundaryElement0; lowerBoundaryElement = lowerBoundaryElement0; } else { LifelineImpl.BoundaryElement boundaryElement = upperBoundaryElement0; if (SDModelUtil.isNested(upperBoundaryElement0.getEntity(), destinationBoundary)) { upperBoundaryElement = upperBoundaryElement0; } else { while (!boundaryElement.isTopNotBottom() || boundaryElement.getEntity() != destinationBoundary) { if (boundaryElement == lowerBoundaryElement0) { return null; } boundaryElement = boundaryElement.getNextBoundaryElement(); } upperBoundaryElement = boundaryElement; } if (SDModelUtil.isNested(lowerBoundaryElement0.getEntity(), destinationBoundary)) { lowerBoundaryElement = lowerBoundaryElement0; } else { while (boundaryElement.isTopNotBottom() || boundaryElement.getEntity() != destinationBoundary) { if (boundaryElement == lowerBoundaryElement0) { return null; } boundaryElement = boundaryElement.getNextBoundaryElement(); } lowerBoundaryElement = boundaryElement; } } return new PasteRange(upperBoundaryElement, lowerBoundaryElement, this); } public SDAnchor getCreateTargetAfterPoint(LifeLineElement lineElementForAnchor) { LifelineImpl.BoundaryElement boundaryElement = (LifelineImpl.BoundaryElement) lineElementForAnchor; if (boundaryElement instanceof LifelineImpl.TopElement) { SDLifeLineElement containerOrSimple = boundaryElement.getEntity(); LifelineImpl.BoundaryElement nextElement = boundaryElement.getNextBoundaryElement(); if (nextElement instanceof LifelineImpl.TopElement) { //"next" element can't be a LifeLine SDBracket anchor = (SDBracket) nextElement.getEntity(); return new SDAnchor(anchor.getBracketContainer(), anchor, true); } else if (nextElement instanceof LifelineImpl.BottomElement) { if (containerOrSimple instanceof SDBracketContainer){ return SDAnchor.firstChildFor((SDBracketContainer)containerOrSimple); } else { SDBracket simpleBracket = (SDBracket)containerOrSimple; return SDAnchor.after(simpleBracket); } } else { throw new RuntimeException(MessageFormat.format("Bad lifeline element {0}", new Object[] { nextElement })); } } else if (boundaryElement instanceof LifelineImpl.BottomElement) { SDLifeLineElement anchor = boundaryElement.getEntity(); if (anchor instanceof SDLifeLine){ throw new RuntimeException("There is nothing after the end of lifeline"); } return SDAnchor.after((SDBracket)anchor); } else { throw new RuntimeException(MessageFormat.format("Bad lifeline element {0}", new Object[] { boundaryElement })); } } public LifelineSatisfyCondition getAfterEntitySatisfyCondition(SDLifeLineElement entity) throws UnknownElementException { final LifelineImpl.BottomElement bottomElement = getBottomElementImpl(entity); class AfterEntitySatisfyCondition implements LifelineSatisfyCondition { public boolean isSatisfied(LifelineElementTraceable elementTraceable) { if (elementTraceable.getLifeLine() != getLifeline()) { throw new IllegalArgumentException("Unexpected lifeline"); } return bottomElement.getNumber() <= elementTraceable.getNumber(); } public LifeLine getLifeline() { return bottomElement.getLifeLine(); } } return new AfterEntitySatisfyCondition(); } public LifelineSatisfyCondition getNotEarlierThanTargetSatisfyCondition(SDAnchor createTarget) throws UnknownElementException { final LifelineElementTraceable beforeTargetElement = (LifelineElementTraceable) getLifeLineElementBeforePoint(createTarget); class NotEarlierThanTargetSatisfyCondition implements LifelineSatisfyCondition { public boolean isSatisfied(LifelineElementTraceable elementTraceable) { if (elementTraceable.getLifeLine() != getLifeline()) { throw new IllegalArgumentException("Unexpected lifeline"); } return beforeTargetElement.getNumber() <= elementTraceable.getNumber(); } public String toString() { return MessageFormat.format("NotEarlierThanTargetSatisfyCondition for {0}", new Object[] { beforeTargetElement }); } public LifeLine getLifeline() { return beforeTargetElement.getLifeLine(); } } return new NotEarlierThanTargetSatisfyCondition(); } public interface ElementLayoutProperties { int getPointOffset(); int getSize(); LifeLineElement.Position getPosition(); } public interface LayoutPropertiesFactory { ElementLayoutProperties createLayoutProperties(SDEntity entity, boolean topNotBottom); } private static final LayoutPropertiesFactory ourNullFactory = new LayoutPropertiesFactory() { public ElementLayoutProperties createLayoutProperties(SDEntity entity, boolean topNotBottom) { return null; } }; private LifelineImpl.BottomElement getBottomElementSecure(SDLifeLineElement lifeLineElement, LifelineImpl lifeLineImpl) throws UnknownElementException { LifelineImpl.BottomElement bottomEntityElement = getBottomElementImpl(lifeLineElement); if (lifeLineImpl != bottomEntityElement.getLifelineImpl()) { throw new RuntimeException("Entity and paste range are from different lifelines"); } return bottomEntityElement; } private LifelineImpl.BottomElement getBottomElementImpl(SDLifeLineElement lifeLineElement) throws UnknownElementException { assert !myIgnoredElements.contains(lifeLineElement); LifelineImpl.BottomElement bottomEntityElement = (LifelineImpl.BottomElement) myLifeLineElement2Bottom.get(lifeLineElement); if (bottomEntityElement == null) { throw new UnknownElementException(MessageFormat.format("Cannot find lifeline element for entity {0}", new Object[] { DebugFormat.debugFormatEntity(lifeLineElement) })); } return bottomEntityElement; } private class FillInputSession { FillInputSession(List<SDLifeLine> lifeLinesEntities, Set<SDBracket> ignoreBrackets, LayoutPropertiesFactory layoutPropertiesFactory) { //System.out.println("[AnchorProcessorInputImpl.FillInputSession] lifeLinesEntities="+lifeLinesEntities); myLayoutPropertiesFactory = layoutPropertiesFactory; myResultLifelines = new ArrayList<LifeLine>(lifeLinesEntities.size()); myIgnoreBrackets = ignoreBrackets; List<LifelineImpl.BoundaryElement> lifeLineTopElements = new ArrayList<LifelineImpl.BoundaryElement>(lifeLinesEntities.size()); List<LifelineImpl.BoundaryElement> lifeLineBottomElements = new ArrayList<LifelineImpl.BoundaryElement>(lifeLinesEntities.size()); myCreationDestructionCollector = new LifelineCreationDestructionCollector(lifeLinesEntities.size()); for (SDLifeLine lifeLineEntity : lifeLinesEntities) { //System.out.println("[AnchorProcessorInputImpl.FillInputSession] another lifeline "+Util.toString(lifeLineEntity)); LifelineImpl lifeLineImpl = new LifelineImpl(NLS.bind("<Lifeline{0}>", new Object[] { DebugFormat.debugFormatEntity(lifeLineEntity) })); LifelineImpl.BottomElement bottomElement = traverseLifeLine(lifeLineEntity, lifeLineImpl); myResultLifelines.add(lifeLineImpl); lifeLineTopElements.add(bottomElement.getTopElement()); lifeLineBottomElements.add(bottomElement); } for (int i = 0; i < myResolveRunnables.size(); i++) { Runnable runnable = (Runnable) myResolveRunnables.get(i); runnable.run(); } //HorizontalConstraintImpl topConstraint = new HorizontalConstraintImpl(lifeLineTopElements); //HorizontalConstraintImpl bottomConstraint = new HorizontalConstraintImpl(lifeLineBottomElements); //System.out.println("[AnchorProcessorInputImpl.FillInputSession] creating top/bottom ("+topConstraint+" "+bottomConstraint+") constrains, sizes: "+lifeLineTopElements.size()+" "+lifeLineBottomElements.size()); } List<LifeLine> getResultLifelines() { return myResultLifelines; } LifelineSatisfyCondition[] createCreationDestructionSatisfyCondition() { return myCreationDestructionCollector.createCreationDestructionSatisfyConditions(myResultLifelines); } LifelineElementTraceable[] getLifelineCreationTops() { return myCreationDestructionCollector.getLifelineCreationTops(); } LifelineElementTraceable[] getLifelineDestructionBottoms() { return myCreationDestructionCollector.getLifelineDestructionBottoms(); } private LifelineImpl.BottomElement traverseLifeLine(SDLifeLine lifeLine, LifelineImpl lifeLineImpl) { final LifelineImpl.TopElement topElement = lifeLineImpl.addTopLifelineElement(lifeLine, myLayoutPropertiesFactory); myCreationDestructionCollector.startLifeline(topElement); traverseLifeLineBracketChildren(lifeLine.getBrackets().iterator(), lifeLineImpl); final LifelineImpl.BottomElement bottomElement = lifeLineImpl.addBottomLifelineElement(topElement, myLayoutPropertiesFactory); myCreationDestructionCollector.finishLifeline(bottomElement); myLifeLineElement2Bottom.put(lifeLine, bottomElement); return bottomElement; } private void traverseLifeLineElement(SDBracket lifeLineElement, LifelineImpl lifeLineImpl) { if (myIgnoreBrackets.contains(lifeLineElement)) { return; } final LifelineImpl.TopElement topElement = lifeLineImpl.addTopLifelineElement(lifeLineElement, myLayoutPropertiesFactory); myCreationDestructionCollector.startElement(topElement); if (lifeLineElement instanceof SDBracketContainer) { SDBracketContainer bracketContainer = (SDBracketContainer) lifeLineElement; traverseLifeLineBracketChildren(bracketContainer.getBrackets().iterator(), lifeLineImpl); } final LifelineImpl.BottomElement bottomElement = lifeLineImpl.addBottomLifelineElement(topElement, myLayoutPropertiesFactory); myCreationDestructionCollector.finishElement(bottomElement); myLifeLineElement2Bottom.put(lifeLineElement, bottomElement); if (lifeLineElement instanceof SDInvocation) { final SDExecution destination = ((SDInvocation) lifeLineElement).getReceiveExecution(); if (destination != null) { if (MissedMethods._executionSpecification().isAsynchronousInvocation((SDInvocation) lifeLineElement)) { //async myResolveRunnables.add(new Runnable() { public void run() { LifelineImpl.BottomElement executionBottomElement = (LifelineImpl.BottomElement) myLifeLineElement2Bottom.get(destination); if (executionBottomElement == null) { return; } LifelineImpl.TopElement executionTopElement = executionBottomElement.getTopElement(); if (executionTopElement.getLifeLine() == topElement.getLifeLine()) { return; } new OrderingConstraintImpl(topElement, executionTopElement); } }); } else { //synch myResolveRunnables.add(new Runnable() { public void run() { LifelineImpl.BottomElement executionBottomElement = (LifelineImpl.BottomElement) myLifeLineElement2Bottom.get(destination); if (executionBottomElement == null) { return; } LifelineImpl.TopElement executionTopElement = executionBottomElement.getTopElement(); if (executionTopElement.getLifeLine() == topElement.getLifeLine()) { return; } new HorizontalConstraintImpl(new LifelineImpl.BoundaryElement[] { bottomElement, executionBottomElement }); new HorizontalConstraintImpl(new LifelineImpl.BoundaryElement[] { topElement, executionTopElement }); } }); } } } else if (lifeLineElement instanceof SDMountingRegion) { SDFrame combinedFragment = findMountingRegionFrame((SDMountingRegion) lifeLineElement); if (combinedFragment != null) { List<SDMountingRegion> regions = myFrame2listOfMountingRegions.get(combinedFragment); if (regions == null) { final ArrayList<SDMountingRegion> createdList = new ArrayList<SDMountingRegion>(3); myResolveRunnables.add(new Runnable() { public void run() { List<LifelineImpl.BoundaryElement> topLifeLineElements = new ArrayList<LifelineImpl.BoundaryElement>(createdList.size()); List<LifelineImpl.BoundaryElement> bottomLifeLineElements = new ArrayList<LifelineImpl.BoundaryElement>(createdList.size()); for (int i = 0; i < createdList.size(); i++) { SDMountingRegion mountingRegion = (SDMountingRegion) createdList.get(i); LifelineImpl.BottomElement mountingRegionBottomElement = (LifelineImpl.BottomElement) myLifeLineElement2Bottom.get(mountingRegion); if (mountingRegionBottomElement == null) { continue; } LifelineImpl.TopElement mountingRegionTopElement = mountingRegionBottomElement.getTopElement(); topLifeLineElements.add(mountingRegionTopElement); bottomLifeLineElements.add(mountingRegionBottomElement); } new HorizontalConstraintImpl(topLifeLineElements); new HorizontalConstraintImpl(bottomLifeLineElements); } }); myFrame2listOfMountingRegions.put(combinedFragment, createdList); regions = createdList; } regions.add((SDMountingRegion) lifeLineElement); } } } private void traverseLifeLineBracketChildren(Iterator<SDBracket> childElements, LifelineImpl lifeLineImpl) { while (childElements.hasNext()) { SDBracket nextBracket = childElements.next(); traverseLifeLineElement(nextBracket, lifeLineImpl); } } private SDFrame findMountingRegionFrame(SDMountingRegion mountingRegion) { return mountingRegion.getFrame(); } private final List<LifeLine> myResultLifelines; private final ArrayList<Runnable> myResolveRunnables = new ArrayList<Runnable>(); private final HashMap<SDFrame, List<SDMountingRegion>> myFrame2listOfMountingRegions = new HashMap<SDFrame, List<SDMountingRegion>>(); private final Set<SDBracket> myIgnoreBrackets; private final LayoutPropertiesFactory myLayoutPropertiesFactory; private LifelineCreationDestructionCollector myCreationDestructionCollector; } private class HorizontalConstraintImpl implements HorizontalConstraint { HorizontalConstraintImpl(List<LifelineImpl.BoundaryElement> boundaryElementsList) { myLifeLineElementsList = new ArrayList<LifeLineElement>(boundaryElementsList); for (LifelineImpl.BoundaryElement boundaryElement : boundaryElementsList) { boundaryElement.setHorizontalConstraint(this); } } HorizontalConstraintImpl(LifelineImpl.BoundaryElement[] lifeLineElements) { myLifeLineElementsList = Arrays.<LifeLineElement> asList(lifeLineElements); for (int i = 0; i < lifeLineElements.length; i++) { lifeLineElements[i].setHorizontalConstraint(this); } } public List<LifeLineElement> getLifeLineElementsList() { return myLifeLineElementsList; } public void elementIsResolved(LifeLineElement lifeLineElement) { } public void elementIsViolated(LifeLineElement lifeLineElement) { } private final List<LifeLineElement> myLifeLineElementsList; } private class OrderingConstraintImpl implements OrderingConstraint { OrderingConstraintImpl(LifelineImpl.BoundaryElement beforeLifeLineElement, LifelineImpl.BoundaryElement afterLifeLineElement) { myBeforeLifeLineElement = beforeLifeLineElement; myAfterLifeLineElement = afterLifeLineElement; beforeLifeLineElement.addAfterConstraints(this); afterLifeLineElement.addBeforeConstraints(this); } public LifeLineElement getBeforeElement() { return myBeforeLifeLineElement; } public LifeLineElement getAfterElement() { return myAfterLifeLineElement; } public int getMinSlopeValue() { return 0; } public void setInvalid(boolean invalid) { } private final LifeLineElement myBeforeLifeLineElement; private final LifeLineElement myAfterLifeLineElement; } private final List<LifeLine> myLifelines; private final LifelineSatisfyCondition[] myCreationDestructionSatisfyConditions; private final LifelineElementTraceable[] myLifelineCreationTops; private final LifelineElementTraceable[] myLifelineDestructionBottoms; private final HashMap<SDLifeLineElement, LifelineImpl.BottomElement> myLifeLineElement2Bottom = new HashMap<SDLifeLineElement, LifelineImpl.BottomElement>(); private final List<SDLifeLine> myLifelinesEntities; private final Map<SDLifeLine, Integer> myLifelineEntity2Index; private final Set<SDBracket> myIgnoredElements; private static abstract class LifeLineElementAdapter implements LifeLineElement, LifelineElementTraceable { public void optimizeSize() { //do nothing by default } public HorizontalConstraint getHorizontalConstraint() { return myHorizontalConstraint; } void setHorizontalConstraint(HorizontalConstraint horizontalConstraint) { if (myHorizontalConstraint != null && horizontalConstraint != null) { throw new IllegalStateException("Horizontal constraint is already set"); } myHorizontalConstraint = horizontalConstraint; } void addBeforeConstraints(OrderingConstraint orderingConstraint) { if (myBeforeConstraintList == null) { myBeforeConstraintList = new ArrayList<OrderingConstraint>(); } myBeforeConstraintList.add(orderingConstraint); } void addAfterConstraints(OrderingConstraint orderingConstraint) { if (myAfterConstraintList == null) { myAfterConstraintList = new ArrayList<OrderingConstraint>(); } myAfterConstraintList.add(orderingConstraint); } public Enumeration<OrderingConstraint> beforeConstraints() { if (myBeforeConstraintList == null) { return EmptyEnumeration.getEnumeration(); } else { return Collections.enumeration(myBeforeConstraintList); } } public Enumeration<OrderingConstraint> afterConstraints() { if (myAfterConstraintList == null) { return EmptyEnumeration.getEnumeration(); } else { return Collections.enumeration(myAfterConstraintList); } } private HorizontalConstraint myHorizontalConstraint; private List<OrderingConstraint> myBeforeConstraintList = null; private List<OrderingConstraint> myAfterConstraintList = null; } private class LifelineImpl implements LifeLine { LifelineImpl(String name) { myName = name; } public LifeLineIterator iterator() { return new LifeLineIterator() { public Integer nextClueValue() { return NULL_CLUE; } public LifeLineElement nextElement() { try { return myCurrentElement; } finally { myCurrentElement = myCurrentElement.nextElement; } } public boolean hasNext() { return myCurrentElement != null; } private BoundaryElement myCurrentElement = myFirstElement; }; } TopElement addTopLifelineElement(SDLifeLineElement entity, LayoutPropertiesFactory layoutPropertiesFactory) { TopElement result = new TopElement(entity, mySize, layoutPropertiesFactory.createLayoutProperties(entity, true)); addElementToList(result); return result; } BottomElement addBottomLifelineElement(TopElement topElement, LayoutPropertiesFactory layoutPropertiesFactory) { BottomElement result = new BottomElement(topElement, mySize, layoutPropertiesFactory.createLayoutProperties(topElement.getEntity(), false)); addElementToList(result); return result; } BoundaryElement getPreviousElement(BoundaryElement boundaryElement) { return boundaryElement.prevElement; } public String toString() { return MessageFormat.format("LL\'{0}\'", new Object[] { myName }); } private void addElementToList(BoundaryElement boundaryElement) { if (myLastElement == null) { myLastElement = boundaryElement; myFirstElement = boundaryElement; boundaryElement.prevElement = null; boundaryElement.nextElement = null; } else { boundaryElement.prevElement = myLastElement; boundaryElement.nextElement = null; myLastElement.nextElement = boundaryElement; myLastElement = boundaryElement; } mySize++; } private BoundaryElement myFirstElement = null; private BoundaryElement myLastElement = null; private int mySize = 0; private final String myName; private abstract class BoundaryElement extends LifeLineElementAdapter { BoundaryElement(int number, ElementLayoutProperties elementLayoutProperties) { myNumber = number; myElementLayoutProperties = elementLayoutProperties; } public LifeLine getLifeLine() { return LifelineImpl.this; } public LifelineImpl getLifelineImpl() { return LifelineImpl.this; } public abstract boolean isTopNotBottom(); abstract SDLifeLineElement getEntity(); public LifelineElementTraceable getPreviousElement() { return this.prevElement; } public LifelineElementTraceable getNextElement() { return this.nextElement; } public BoundaryElement getPreviousBoundaryElement() { return this.prevElement; } public BoundaryElement getNextBoundaryElement() { return this.nextElement; } public int getNumber() { return myNumber; } public int getPointOffset() { return myElementLayoutProperties.getPointOffset(); } public int getSize() { return myElementLayoutProperties.getSize(); } public Position getPosition() { return myElementLayoutProperties.getPosition(); } BoundaryElement nextElement; BoundaryElement prevElement; private final int myNumber; private final ElementLayoutProperties myElementLayoutProperties; } private class TopElement extends BoundaryElement { TopElement(SDLifeLineElement entity, int number, ElementLayoutProperties elementLayoutProperties) { super(number, elementLayoutProperties); myEntity = entity; } public boolean isTopNotBottom() { return true; } SDLifeLineElement getEntity() { return myEntity; } public String toString() { return MessageFormat.format("[TopOf({0}){1}]", new Object[] { DebugFormat.debugFormatEntity(getEntity()), getNumber() }); } public SDLifeLineElement getEntityAfterElement() { return myEntity; } private final SDLifeLineElement myEntity; } private class BottomElement extends BoundaryElement { BottomElement(TopElement topElement, int number, ElementLayoutProperties elementLayoutProperties) { super(number, elementLayoutProperties); myTopElement = topElement; } public boolean isTopNotBottom() { return false; } SDLifeLineElement getEntity() { return myTopElement.getEntity(); } TopElement getTopElement() { return myTopElement; } public SDLifeLineElement getEntityAfterElement() { if (getEntity() instanceof SDLifeLine){ return null; } SDBracket bracket = (SDBracket) getEntity(); return bracket.getBracketContainer(); } public String toString() { return MessageFormat.format("[BottomOf({0}){1}]", new Object[] { DebugFormat.debugFormatEntity(getEntity()), getNumber() }); } private final TopElement myTopElement; } } private static class LifelineCreationDestructionCollector { LifelineCreationDestructionCollector(int lifelineCount) { myLifelineCreation = new LifelineImpl.TopElement[lifelineCount]; myLifelineDestruction = new LifelineImpl.BottomElement[lifelineCount]; } void startLifeline(LifelineImpl.TopElement lifelineTop) { myCurrentLifelineIndex++; } void finishLifeline(LifelineImpl.BottomElement lifelineBottom) { } void startElement(LifelineImpl.TopElement topElement) { if (myLifelineCreation[myCurrentLifelineIndex] != null) { return; } SDEntity entity = topElement.getEntity(); if (entity instanceof SDExecution && MissedMethods._executionSpecification().isCreation((SDExecution) entity)) { myLifelineCreation[myCurrentLifelineIndex] = topElement; } } void finishElement(LifelineImpl.BottomElement bottomElement) { SDEntity entity = bottomElement.getEntity(); if (entity instanceof SDExecution && MissedMethods._executionSpecification().isDestruction((SDExecution) entity)) { myLifelineDestruction[myCurrentLifelineIndex] = bottomElement; } } LifelineElementTraceable[] getLifelineCreationTops() { return myLifelineCreation; } LifelineElementTraceable[] getLifelineDestructionBottoms() { return myLifelineDestruction; } LifelineSatisfyCondition[] createCreationDestructionSatisfyConditions(List<LifeLine> lifeilneImplList) { LifelineSatisfyCondition[] result = new LifelineSatisfyCondition[lifeilneImplList.size()]; class NoElementsBeforeCreationOrAfterDestruction implements LifelineSatisfyCondition { NoElementsBeforeCreationOrAfterDestruction(LifelineImpl lifeline, LifelineImpl.TopElement creation, LifelineImpl.BottomElement destruction) { myLifeline = lifeline; myCreation = creation; myDestruction = destruction; } public boolean isSatisfied(LifelineElementTraceable elementTraceable) { if (myCreation != null) { if (elementTraceable.getNumber() < myCreation.getNumber()) { return false; } } if (myDestruction != null) { if (myDestruction.getNumber() <= elementTraceable.getNumber()) { return false; } } return true; } public LifeLine getLifeline() { return myLifeline; } private final LifelineImpl myLifeline; private final LifelineImpl.TopElement myCreation; private final LifelineImpl.BottomElement myDestruction; } for (int i = 0; i < myLifelineCreation.length; i++) { if (myLifelineCreation[i] != null || myLifelineDestruction[i] != null) { result[i] = new NoElementsBeforeCreationOrAfterDestruction((LifelineImpl) lifeilneImplList.get(i), myLifelineCreation[i], myLifelineDestruction[i]); } } return result; } private final LifelineImpl.TopElement[] myLifelineCreation; private final LifelineImpl.BottomElement[] myLifelineDestruction; private int myCurrentLifelineIndex = -1; } }