Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
rapture.dp.WorkflowLayoutUtil Maven / Gradle / Ivy
package rapture.dp;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import rapture.common.dp.Step;
import rapture.common.dp.Transition;
import rapture.common.dp.Workflow;
import rapture.common.dp.WorkflowArrowLayout;
import rapture.common.dp.WorkflowBoxLayout;
import rapture.common.dp.WorkflowColumnLayout;
import rapture.common.dp.WorkflowGridLayout;
import rapture.dp.WorkflowLayoutUtil.BoxNote.Kind;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class WorkflowLayoutUtil {
private static final Logger log = Logger.getLogger(WorkflowLayoutUtil.class);
public static WorkflowGridLayout makeGridLayout (Workflow workflow ) {
if (log.isTraceEnabled()) log.trace("Making layout from scratch for " + workflow.getWorkflowURI());
return new LayoutMaker(workflow).make();
}
private static class LayoutMaker {
final WorkflowGridLayout result = new WorkflowGridLayout();
final Map name2note = Maps.newHashMap();
final List boxes = Lists.newArrayList();
final List panels = Lists.newArrayList();
final Workflow workflow;
final Map num2col = Maps.newHashMap();
int idCount = 0 ;
private LayoutMaker (Workflow workflow ) {
this .workflow = workflow;
}
WorkflowGridLayout make ( ) {
result.setArrows(new ArrayList());
result.setColumns(new ArrayList());
for (Step step : workflow.getSteps()) {
BoxNote note = new BoxNote(step);
name2note.put(step.getName(), note);
boxes.add (note);
}
BoxNote startBox = new BoxNote(Kind.START);
Panel startPanel = new Panel(startBox, null );
BoxNote startStep = name2note.get (workflow.getStartStep());
if (startStep != null ) mapIsland(startBox, startStep, startPanel);
panels.add (startPanel);
for (BoxNote note : boxes) {
if (note.panel == null ) {
Panel panel = new Panel(note, null );
mapIsland(note, null , panel);
panels.add (panel);
}
}
int left = 0 ;
for (Panel panel : panels) {
int min = panel.minX();
int max = panel.maxX();
int offset = left - min;
left += min - max;
for (BoxNote note : panel.boxNotes) {
note.gx = note.pgx + offset;
note.gy = note.pgy;
}
}
for (BoxNote note : boxes) {
WorkflowBoxLayout box = note.box;
if (box == null ) box = makeWorkflowBoxLayout(note);
getOrMakeColumn(note.gx).getBoxes().add (box);
for (ArrowNote arrowNote : note.inArrows) {
WorkflowArrowLayout arrow = new WorkflowArrowLayout();
arrow.setFromBoxName(getOrMakeBoxId(arrowNote.source));
arrow.setName(n2e(arrowNote.t.getName()));
result.getArrows().add (arrow);
}
}
List columnKeys = Lists.newArrayList(num2col.keySet());
Collections.sort(columnKeys);
for (Integer key : columnKeys) {
result.getColumns().add (num2col.get (key));
}
result.setWorkflowURI(workflow.getWorkflowURI());
return result;
}
private String n2e (String in ) {
return (in == null ) ? "" : in ;
}
private String getOrMakeBoxId (BoxNote note ) {
if (note.box == null ) makeWorkflowBoxLayout(note);
return note.box.getId();
}
private WorkflowColumnLayout getOrMakeColumn (int col ) {
WorkflowColumnLayout column = num2col.get (col);
if (column == null ) {
column = new WorkflowColumnLayout();
column.setColumnNumber(col);
num2col.put(col, column);
}
return column;
}
private WorkflowBoxLayout makeWorkflowBoxLayout (BoxNote note ) {
WorkflowBoxLayout result = new WorkflowBoxLayout();
result.setGx(note.gx);
result.setGy(note.gy);
if (note.kind == Kind.STEP) {
result.setName(note.step.getName());
} else {
result.setName("" );
}
result.setKind(note.kind.toString());
result.setId(nextId());
note.box = result;
return result;
}
private String nextId ( ) {
idCount++;
return "_" + idCount;
}
private void mapIsland (BoxNote next, BoxNote previous, Panel panel ) {
if (previous == null ) {
next.pgx = 0 ;
next.pgy = 0 ;
} else {
panel.placeNear(next, previous);
}
mapForward(next, panel);
mapReverse(next, panel);
}
private void mapForward (BoxNote from , Panel panel ) {
List nextGen = Lists.newArrayList();
for (Transition t : from .step.getTransitions()) {
if (StringUtils.isEmpty(t.getName())) handleTransition(t, from , panel, nextGen);
}
for (Transition t : from .step.getTransitions()) {
if (!StringUtils.isEmpty(t.getName())) handleTransition(t, from , panel, nextGen);
}
for (BoxNote note : nextGen) {
mapForward(note, panel);
}
}
private void handleTransition (Transition t, BoxNote from , Panel panel, List future ) {
String toName = t.getTargetStep();
BoxNote toNote = name2note.get (toName);
if (toNote == null ) {
toNote = makeBoxNoteFromToName(toName, panel, from , future);
name2note.put(toName, toNote);
}
toNote.addArrow(from , t);
if (toNote.panel == null ) {
panel.placeNear(toNote, from );
}
}
private static final Transition JOIN_TRANSITION;
static {
JOIN_TRANSITION = new Transition();
JOIN_TRANSITION.setName("" );
JOIN_TRANSITION.setTargetStep("$JOIN" );
}
private BoxNote makeBoxNoteFromToName (String toName, Panel parent, BoxNote fromNote, List future ) {
BoxNote result = new BoxNote();
if (toName.startsWith("$" )) {
if (toName.startsWith("$RETURN" )) {
result.kind = Kind.RETURN;
if (toName.startsWith("$RETURN:" )) {
result.decoration = toName.substring("$RETURN:" .length());
}
} else if (toName.startsWith("$JOIN" )) {
result.kind = Kind.JOIN;
parent.tails.add (result);
}
} else {
BoxNote note = name2note.get (toName);
if (note == null ) {
result.decoration = toName;
result.kind = Kind.UNDEFINED;
return result;
} else {
if (note.step != null ) {
if (note.step.getExecutable().startsWith("$SPLIT:" )) {
if (note.panel != null ) {
return note;
}
result.kind = Kind.SPLIT;
String forkNames[] = toName.substring("$SPLIT:" .length()).split("," );
List forkPanels = Lists.newArrayList();
for (String forkName : forkNames) {
Panel p = makePanelForCall(forkName, parent);
forkPanels.add (p);
}
int width = 0 ;
int height = 1 ;
for (Panel p : forkPanels) {
width += p.getWidth();
int pHeight = p.getHeight();
if (pHeight > height) height = pHeight;
}
result.gw = width > 0 ? width : 1 ;
Point pos = parent.findVacantBlock(width, height + 2 , fromNote);
parent.placeAt(pos.x, pos.y, result, true );
BoxNote footer = new BoxNote(Kind.JOIN);
footer.step = note.step;
parent.placeAt(pos.x, pos.y + height + 1 , footer, isTail(footer));
int x = pos.x;
for (Panel p : forkPanels) {
parent.transfer(x, pos.y + 1 , p);
for (BoxNote tail : p.tails) {
footer.addArrow(tail, JOIN_TRANSITION);
}
}
future.add (footer);
return note;
} else if (note.step.getExecutable().startsWith("$FORK:" )) {
} else if (note.step.getExecutable().startsWith("$FAIL" )) {
note.kind = Kind.ERROR;
return note;
} else if (note.step.getExecutable().startsWith("$RETURN" )) {
note.kind = Kind.RETURN;
if (note.step.getExecutable().startsWith("$RETURN:" )) {
note.decoration = note.step.getExecutable().substring("$RETURN:" .length());
}
return note;
}
}
future.add (note);
return note;
}
}
return result;
}
private boolean isTail (BoxNote note ) {
List ts = note.step.getTransitions();
if (ts == null ) return false ;
for (Transition t : ts) {
if (t.getTargetStep().startsWith("$JOIN" )) return true ;
}
return false ;
}
private Panel makePanelForCall (String stepName, Panel parent ) {
BoxNote root = name2note.get (stepName);
if (root == null ) {
BoxNote call = new BoxNote(Kind.CALL);
Panel p = new Panel(call, parent);
p.tails.add (call);
}
Panel result = new Panel(root, parent);
mapIsland(root, null , result);
return result;
}
private void mapReverse (BoxNote from , Panel panel ) {
}
}
static class BoxNote {
public WorkflowBoxLayout box;
BoxNote(Step step) {
this .step = step;
this .kind = Kind.STEP;
}
BoxNote(Kind k) {
kind = k;
}
BoxNote() {
this .kind = Kind.UNDEFINED;
}
enum Kind {
STEP, START, RETURN, ERROR, UNDEFINED, SPLIT, JOIN, FORK, CALL
};
void addArrow (BoxNote from , Transition t ) {
inArrows.add (new ArrowNote(from , t));
}
Kind kind;
Panel panel = null ;
Integer pgx = null ;
Integer pgy = null ;
Integer gx = null ;
Integer gy = null ;
int gw = 1 ;
Step step;
String decoration = null ;
List inArrows = Lists.newArrayList();
}
static class ArrowNote {
final Transition t;
final BoxNote source;
ArrowNote(BoxNote from , Transition t) {
this .t = t;
this .source = from ;
}
}
static class Panel {
final Panel parent;
final List boxNotes = Lists.newArrayList();
final List heads = Lists.newArrayList();
final List tails = Lists.newArrayList();
Panel(BoxNote anchor, Panel parent) {
this .parent = parent;
anchor.pgx = 0 ;
anchor.pgy = 0 ;
boxNotes.add (anchor);
heads.add (anchor);
}
public void transfer (int x, int y, Panel p ) {
for (BoxNote note : boxNotes) {
placeAt(x + note.pgx, y + note.pgy, note);
}
}
public int minX ( ) {
int result = Integer.MAX_VALUE;
for (BoxNote note : boxNotes) {
if (note.pgx < result) result = note.pgx;
}
return result;
}
public int maxX ( ) {
int result = Integer.MIN_VALUE;
for (BoxNote note : boxNotes) {
if (note.pgx > result) result = note.pgx;
}
return result;
}
public int minY ( ) {
int result = Integer.MAX_VALUE;
for (BoxNote note : boxNotes) {
if (note.pgy < result) result = note.pgy;
}
return result;
}
public int maxY ( ) {
int result = Integer.MIN_VALUE;
for (BoxNote note : boxNotes) {
if (note.pgy > result) result = note.pgy;
}
return result;
}
public int getWidth ( ) {
return maxX() - minX() + 1 ;
}
public int getHeight ( ) {
return maxY() - minY() + 1 ;
}
public boolean isVacant (int x, int y ) {
for (BoxNote note : boxNotes) {
if (note.pgx >= x && note.pgx + note.gw <= x && note.pgy == y) return false ;
}
return true ;
}
boolean placeAt (int x, int y, BoxNote note ) {
return placeAt(x, y, note, true );
}
boolean placeAt (int x, int y, BoxNote note, boolean isTail ) {
if (isVacant(x, y)) {
note.pgx = x;
note.pgy = y;
note.panel = this ;
if (isTail) tails.add (note);
return true ;
}
return false ;
}
void placeNear (BoxNote note, BoxNote near ) {
int fx = near.pgx;
int fy = near.pgy;
if (!placeAt(fx, fy + 1 , note)) if (!placeAt(fx + 1 , fy, note)) if (!placeAt(fx - 1 , fy, note)) {
if (!placeAt(fx - 1 , fy + 1 , note)) if (!placeAt(fx + 1 , fy + 1 , note)) {
}
}
}
Point findVacantBlock (int width, int height, BoxNote near ) {
int sx = near.gx;
int sy = near.gy + 1 ;
if (isVacantBlock(sx, sy, width, height)) return new Point(sx, sy);
int roam = 1 ;
while (true ) {
if (isVacantBlock(sx + roam, sy, width, height)) return new Point(sx, sy);
if (isVacantBlock(sx, sy + roam, width, height)) return new Point(sx, sy);
if (isVacantBlock(sx - roam, sy, width, height)) return new Point(sx, sy);
roam++;
}
}
boolean isVacantBlock (int x, int y, int w, int h ) {
for (int i = 0 ; i < w; i++) {
for (int j = 0 ; j < h; j++) {
if (!isVacant(x + i, y + j)) return false ;
}
}
return true ;
}
}
}