KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > jawe > ProcessGraph


1 /* ProcessGraph.java
2  *
3  * Authors:
4  * Stefanovic Nenad chupo@iis.ns.ac.yu
5  * Bojanic Sasa sasaboy@neobee.net
6  * Puskas Vladimir vpuskas@eunet.yu
7  * Pilipovic Goran zboniek@uns.ac.yu
8  *
9  */

10
11 package org.enhydra.jawe;
12
13 import org.enhydra.jawe.actions.*;
14 import org.enhydra.jawe.graph.*;
15 import org.enhydra.jawe.xml.*;
16 import org.enhydra.jawe.xml.elements.WorkflowProcess;
17
18 import org.jgraph.*;
19 import org.jgraph.graph.*;
20 import org.jgraph.plaf.basic.*;
21 import java.awt.*;
22 import java.awt.print.*;
23 import java.awt.event.*;
24 import java.util.*;
25 import java.io.*;
26 import javax.swing.*;
27 import javax.swing.border.*;
28 import javax.swing.tree.DefaultMutableTreeNode JavaDoc;
29 import org.enhydra.jawe.PackageEditor;
30
31 /**
32  * JaWE implementation of JGraph. Represents a process graph.
33  */

34 public class ProcessGraph extends AbstractGraph {
35
36    /**
37     * Constructs process graph based on a given model.
38     */

39    public ProcessGraph(GraphModel model,ProcessEditor pe) {
40       super(model,pe);
41    }
42
43    public ProcessGraph(GraphModel model,GraphLayoutCache view) {
44       super(model,view);
45    }
46
47
48    protected void initGraphBehavior() {
49       super.initGraphBehavior();
50       setMoveable(true);
51       setDisconnectable(true);
52       setDisconnectOnMove(false);
53       selectionModel.setSelectionMode(
54          GraphSelectionModel.MULTIPLE_GRAPH_SELECTION);
55    }
56
57
58    public org.enhydra.jawe.xml.elements.Package getXMLPackage () {
59       return ((org.enhydra.jawe.xml.elements.WorkflowProcess)
60                  xmlObject).getPackage();
61    }
62
63    public void setPropertyObject (XMLComplexElement wp) {
64       xmlObject=wp;
65       // disable graph if this is an external package
66
org.enhydra.jawe.xml.elements.Package myP=
67          ((org.enhydra.jawe.xml.elements.WorkflowProcess)xmlObject).
68          getPackage();
69       if (myP!=JaWE.getInstance().getRealXMLPackage()) {
70          super.initGraphBehavior();
71       }
72    }
73
74    public void createWorkflowGraph (Window notInUse) {
75       workflowManager.createWorkflowGraph(
76                                             (org.enhydra.jawe.xml.elements.WorkflowProcess)xmlObject);
77       editor.resetUndoManager();
78    }
79
80    /**
81     * Overrides Superclass method.
82     */

83    public String JavaDoc convertValueToString(Object JavaDoc value) {
84       if (value instanceof CellView) {
85          value=((CellView)value).getCell();
86       }
87       if (value instanceof DefaultMutableTreeNode JavaDoc &&
88           !(value instanceof Transition) &&
89           !(value instanceof Start) &&
90           !(value instanceof End) &&
91              ((DefaultMutableTreeNode JavaDoc)value).getUserObject() != null) {
92          return ((DefaultMutableTreeNode JavaDoc)value).getUserObject().toString();
93       } else if (value != null) {
94          return value.toString();
95       }
96       return null;
97    }
98
99    /**
100     * Override Superclass Method to Return Custom vertexView.
101     */

102    protected VertexView createVertexView(JGraph graph,CellMapper cm,Object JavaDoc cell) {//HM, JGraph3.4.1
103
if (cell instanceof Participant) {
104          return new ParticipantView(cell,this,cm);
105       } else if (cell instanceof Subflow) {
106          return new SubflowView(cell,this,cm);
107       } else if (cell instanceof BlockActivity) {
108          return new BlockActivityView(cell,this,cm);
109       } else if (cell instanceof Start) {
110          return new StartView(cell,this,cm);
111       } else if (cell instanceof End) {
112          return new EndView(cell,this,cm);
113       } else if (cell instanceof Route) {
114          return new RouteView(cell,this,cm);
115       } else if (cell instanceof Activity) {
116          return new ActivityView(cell,this,cm);
117       } else {
118          //return super.createVertexView(this,cm,cell);//HM, JGraph3.4.1
119
return super.createVertexView(graph,cm,cell);//HM, JGraph3.4.1
120
}
121    }
122
123    /**
124     * Override Superclass Method to Return Custom EdgeView.
125     */

126    protected EdgeView createEdgeView(JGraph graph, CellMapper cm,Object JavaDoc e) {//HM, JGraph3.4.1
127
if (e instanceof Transition) {
128          return new TransitionView(e,this, cm);
129       }
130       else {
131          //return super.createEdgeView(this,cm,e);//HM, JGraph3.4.1
132
return super.createEdgeView(graph,cm,e);//HM, JGraph3.4.1
133
}
134    }
135
136    /**
137     * Override Superclass Method to Return Custom PortView.
138     */

139    //protected PortView createPortView(JGraph graph,CellMapper cm,Port p) {//HM, JGraph3.4.1
140
protected PortView createPortView(JGraph graph,CellMapper cm,Object JavaDoc o) {//HM, JGraph3.4.1
141
return new JaWEPortView(o,this,cm);
142    }
143
144    /**
145     * Finds the topmost Participant at specified location.
146     */

147    public Object JavaDoc getFirstParticipantForLocation(int x,int y) {
148       x /= scale; y /= scale; // FIX: Consistency with other methods?
149
CellView[] cells = getOrderedAllSelectableCells();
150       if (cells != null) {
151          Rectangle r = new Rectangle(x-tolerance,y-tolerance,2*tolerance,2*tolerance);
152          // Iterate through cells and find first Participant at
153
// if current is traversed. Cache first cell.
154
CellView first = null;
155          for (int i=0; i<cells.length; i++) {
156             if (cells[i] instanceof ParticipantView) {
157                boolean intersects=cells[i].getBounds().intersects(r);
158                if (intersects) {
159                   return cells[i].getCell();
160                }
161             }
162          }
163       }
164       return null;
165    }
166
167    /**
168     * Modified from original to support all views
169     */

170    public CellView getNextViewAt(CellView current, double x, double y) {//HM, JGraph3.4.1
171
CellView[] sel = getOrderedAllSelectableCells();
172       CellView cell = getNextViewAt(sel, current, x, y);
173       return cell;
174    }
175
176    /**
177     * Modified from original to suite our needs. This method makes a Participant
178     * to be selected only when it's name part is pressed, and to give it's
179     * tooltip only when you want to insert some cells in it.
180     */

181    public CellView getNextViewAt(CellView[] cells, CellView c, double x, double y) {//HM, JGraph3.4.1
182
if (cells != null) {
183          Rectangle r = new Rectangle((int)x-tolerance,(int)y-tolerance,2*tolerance,2*tolerance);//HM, JGraph3.4.1
184
// Iterate through cells and switch to active
185
// if current is traversed. Cache first cell.
186
CellView first = null;
187          boolean active = (c == null);
188          for (int i=0; i<cells.length; i++) {
189             boolean intersects=false;
190             boolean wholeArea=true;
191             if (((JaWEMarqueeHandler)marquee).getSelectButton().isSelected() ||
192                    ((JaWEMarqueeHandler)marquee).getTransitionButton().isSelected() ||
193                    ((JaWEMarqueeHandler)marquee).getSelfRoutedTransitionButton().isSelected() ||
194                    ((JaWEMarqueeHandler)marquee).getCircularTransitionButton().isSelected()) {
195                wholeArea=false;
196             }
197             if ((cells[i] instanceof ParticipantView) && wholeArea) {
198                intersects=cells[i].getBounds().intersects(r);
199             }
200             else {
201                intersects=cells[i].intersects(getGraphics(), r);
202             }
203
204             if (intersects) {
205                if (active) {
206                   return cells[i];
207                }
208                else if (first == null) {
209                   first = cells[i];
210                }
211                active = active | (cells[i] == c);
212             }
213          }
214          return first;
215       }
216       return null;
217    }
218
219    /**
220     * This method gets all selectable views and puts it in an order that suites to
221     * our needs (first comes activities and transitions(edges), and then Participants sorted
222     * by level - root Participants comes last)
223     */

224    private CellView[] getOrderedAllSelectableCells () {
225       // Get Roots in View Order
226
CellView[] views = graphLayoutCache.getRoots();
227       // Add Roots to Stack
228
Stack s = new Stack();
229       for (int i = 0; i < views.length; i++) {
230          s.add(views[i]);
231       }
232       java.util.List JavaDoc result = new ArrayList();
233       // Traverse All Children In View Order
234
while (!s.isEmpty()) {
235          CellView view = (CellView)s.pop();
236          Object JavaDoc cell=view.getCell();
237          // Add To List if it is not a port or forbidden object
238
if (!(cell instanceof Port)) {// && !(cell instanceof SubflowPort)) {
239
result.add(view);
240          }
241          // Add Children to Stack
242
CellView[] children = view.getChildViews();
243          for (int i = 0; i < children.length; i++) {
244             s.add(children[i]);
245          }
246       }
247       // Order so that all activities comes first, after that Participants in ordered view
248

249       // first iteration - separating Participants and others
250
java.util.List JavaDoc activitiesAndEdges = new ArrayList();
251       java.util.List JavaDoc participants = new ArrayList();
252       Iterator it = result.iterator();
253       while (it.hasNext()) {
254          CellView cv=(CellView)it.next();
255          if (cv.getCell() instanceof Participant) {
256             participants.add(cv);
257          }
258          else {
259             activitiesAndEdges.add(cv);
260          }
261       }
262
263       // second iteration - order, first adding activities & edges and then
264
// Participants in reversed order: it must be done that way because the
265
// child views of Participants (activities) that had focus more recently
266
// has higher number and are placed closer to the begining of
267
// activitiesAndEdges set, but on contrary, Participants that has higher
268
// depth (and should have focus before their parents) are placed closer
269
// to the end of Participants set
270
int i = -1;
271       int j=participants.size()+activitiesAndEdges.size();
272       CellView[] tmp = new CellView[j];
273
274       it=activitiesAndEdges.iterator();
275       while (it.hasNext()) {
276          tmp[++i] = (CellView)it.next();
277       }
278
279       it=participants.iterator();
280       while (it.hasNext()) {
281          tmp[--j] = (CellView)it.next();
282       }
283
284       return tmp;
285    }
286
287    /**
288     * Only for debugging purpose.
289     */

290    public void printOrderedAllSelectables() {
291       CellView[] sel = getOrderedAllSelectableCells();
292       for (int i=0; i<sel.length; i++)
293          System.out.println("view"+i+"="+sel[i].getCell());
294    }
295
296    /**
297     * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
298     * method in order to allow the graph controller to create a tooltip
299     * for the topmost cell under the mousepointer. This differs from JTree
300     * where the renderers tooltip is used.
301     * <p>
302     * NOTE: For <code>JGraph</code> to properly display tooltips of its
303     * renderers, <code>JGraph</code> must be a registered component with the
304     * <code>ToolTipManager</code>. This can be done by invoking
305     * <code>ToolTipManager.sharedInstance().registerComponent(graph)</code>.
306     * This is not done automatically!
307     * @param event the <code>MouseEvent</code> that initiated the
308     * <code>ToolTip</code> display
309     * @return a string containing the tooltip or <code>null</code>
310     * if <code>event</code> is null
311     */

312    public String JavaDoc getToolTipText(MouseEvent event) {
313       if(event != null) {
314          Object JavaDoc cell;
315          // if activity or Participant is to be inserted, show
316
// underlying Participant, else show other
317
if (!(((JaWEMarqueeHandler)marquee).getSelectButton().isSelected() ||
318                   ((JaWEMarqueeHandler)marquee).getTransitionButton().isSelected() ||
319                   ((JaWEMarqueeHandler)marquee).getSelfRoutedTransitionButton().isSelected()) ||
320                 ((JaWEMarqueeHandler)marquee).getCircularTransitionButton().isSelected()) {
321             cell=getFirstParticipantForLocation(event.getX(),event.getY());
322          }
323          else {
324             cell=getFirstCellForLocation(event.getX(),event.getY());
325          }
326          if (cell != null) {
327             String JavaDoc s=convertValueToString(cell);
328
329             if (cell instanceof WorkflowElement) {
330                s=((WorkflowElement)cell).getTooltip();
331             }
332             return s;
333          }
334       }
335       return null;
336    }
337
338    public void setAdditionalKeyboardShortcuts () {
339       super.setAdditionalKeyboardShortcuts();
340       getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
341          .put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE,InputEvent.ALT_DOWN_MASK,false),
342               Utils.getUnqualifiedClassName(HideWindow.class));
343       getActionMap().put(Utils.getUnqualifiedClassName(HideWindow.class),
344                          editor.getAction(Utils.getUnqualifiedClassName(HideWindow.class)));
345    }
346
347    public boolean validateAgainsXPDLSchema () {
348       return true;
349    }
350
351    public boolean checkConnections (boolean fullCheck) {
352       updateXMLObjectsBeforeChecking();
353       PackageValidator pv=new PackageValidator(getXMLPackage(),true,true,false,false,
354                                                JaWEConfig.getInstance().getAllowUndefinedStartActivity(),
355                                                JaWEConfig.getInstance().getAllowUndefinedEndActivity(),
356                                                JaWEConfig.getInstance().getEncoding());
357       XMLCollectionElement wpOrAs=(XMLCollectionElement)getXPDLObject();
358       boolean isGraphWellConnected=pv.checkGraphConnections(wpOrAs,fullCheck);
359       basicGraphConnectionError=pv.getBasicGraphConnectionError(wpOrAs);
360       graphConnectionErrors=pv.getGraphsConnectionErrors(wpOrAs);
361       if (JaWEConfig.getInstance().getUseBubblesStatus() && (fullCheck || isGraphWellConnected)) {
362          isGraphWellConnected=checkStartAndEndsConnections(fullCheck) && isGraphWellConnected;
363       }
364       return isGraphWellConnected;
365    }
366
367    protected boolean checkStartAndEndsConnections (boolean fullCheck) {
368       boolean wellConnected=true;
369       WorkflowProcess wp=(WorkflowProcess)getPropertyObject();
370       if (graphConformanceErrors==null) {
371          graphConformanceErrors=new HashMap();
372       }
373
374       // check start's and end's connections
375
Set icStarts=getImproperlyConnectedStarts(fullCheck);
376       if (icStarts.size()>0) {
377          wellConnected=false;
378          basicGraphConnectionError=ResourceManager.
379             getLanguageDependentString("InformationOneOrMoreElementsAreNotProperlyConnected");
380          if (fullCheck) {
381             for (Iterator i=icStarts.iterator(); i.hasNext();) {
382                Activity s=(Activity)i.next();
383                if (s instanceof Start) {
384                   graphConnectionErrors.put(s,ResourceManager.getLanguageDependentString("ErrorConnectionToStartingActivityIsMissing")+"; ");
385                } else {
386                   String JavaDoc msg=(String JavaDoc)graphConnectionErrors.get(s.getPropertyObject());
387                   msg=PackageValidator.prepareMessageString(msg);
388                   msg=msg+ResourceManager.getLanguageDependentString("ErrorIncomingTransitionOrConnectionFromStartBubbleIsMissing");
389                   graphConnectionErrors.put(s.getPropertyObject(),msg);
390                }
391             }
392          }
393       }
394
395       if (fullCheck || wellConnected) {
396          Set icEnds=getImproperlyConnectedEnds(fullCheck);
397          if (icEnds.size()>0) {
398             wellConnected=false;
399             basicGraphConnectionError=ResourceManager.
400                getLanguageDependentString("InformationOneOrMoreElementsAreNotProperlyConnected");
401             if (fullCheck) {
402                for (Iterator i=icEnds.iterator(); i.hasNext();) {
403                   Activity e=(Activity)i.next();
404                   if (e instanceof End) {
405                      if (e.getIncomingTransitions().size()==0) {
406                         graphConnectionErrors.put(e,ResourceManager.getLanguageDependentString("ErrorConnectionFromEndingActivityIsMissing")+"; ");
407                      } else {
408                         graphConnectionErrors.put(e,ResourceManager.getLanguageDependentString("ErrorNotConnectedToEndingActivity")+"; ");
409                      }
410                   } else {
411                      String JavaDoc msg=(String JavaDoc)graphConnectionErrors.get(e.getPropertyObject());
412                      msg=PackageValidator.prepareMessageString(msg);
413                      msg=msg+ResourceManager.getLanguageDependentString("ErrorOutgoingTransitionOrConnectionToEndBubbleIsMissing");
414                      graphConnectionErrors.put(e.getPropertyObject(),msg);
415                   }
416                }
417             }
418          }
419       }
420
421       if (fullCheck || wellConnected) {
422          // find all block activities
423
Set blockActs=workflowManager.getBlockActivities(true);
424          Iterator itBas=blockActs.iterator();
425          while (itBas.hasNext()) {
426             BlockActivity ba=(BlockActivity)itBas.next();
427             ProcessEditor bwe=ba.getImplementationEditor();
428             if (bwe!=null) {
429                ProcessGraph bag=(ProcessGraph)bwe.getGraph();
430                if (bag.getImproperlyConnectedStarts(false).size()>0 ||
431                    bag.getImproperlyConnectedEnds(false).size()>0) {
432                   wellConnected=false;
433                   basicGraphConnectionError=ResourceManager.
434                      getLanguageDependentString("InformationOneOrMoreElementsAreNotProperlyConnected");
435                   if (!fullCheck){
436                      break;
437                   }
438                   String JavaDoc m=ResourceManager.getLanguageDependentString("ErrorInnerTransitionError");
439                   String JavaDoc msg=(String JavaDoc)graphConnectionErrors.get(ba.getUserObject());
440                   msg=PackageValidator.prepareMessageString(msg);
441                   msg=msg+m;
442                   graphConnectionErrors.put(ba.getUserObject(),msg);
443                }
444
445             }
446          }
447       }
448       return wellConnected;
449    }
450
451    public Set getImproperlyConnectedStarts (boolean fullCheck) {
452       Set icStarts=new HashSet();
453
454       Set allActivities=((JaWEGraphModel)graphModel).getAllActivitiesInModel(graphModel);
455       if (allActivities!=null) {
456          Iterator it=allActivities.iterator();
457          while (it.hasNext()) {
458             Activity act=(Activity)it.next();
459             if (act instanceof Start) {
460                if (act.getOutgoingTransitions().size()==0) {
461                   icStarts.add(act);
462                   if (!fullCheck) {
463                      break;
464                   }
465                }
466             } else if (!(act instanceof End)) {
467                Set incomingTrans=act.getIncomingTransitions();
468                if (incomingTrans.size()==0) {
469                   icStarts.add(act);
470                   if (!fullCheck) {
471                      break;
472                   }
473                } else if (incomingTrans.size()==1) {
474                   if (Utils.hasCircularTransitions(incomingTrans)) {
475                      icStarts.add(act);
476                      if (!fullCheck) {
477                         break;
478                      }
479                   }
480                }
481             }
482          }
483       }
484       return icStarts;
485    }
486
487    public Set getImproperlyConnectedEnds (boolean fullCheck) {
488       Set icEnds=new HashSet();
489
490       Set allActivities=((JaWEGraphModel)graphModel).getAllActivitiesInModel(graphModel);
491       if (allActivities!=null) {
492          Iterator it=allActivities.iterator();
493          while (it.hasNext()) {
494             Activity act=(Activity)it.next();
495             if (act instanceof End) {
496                Set incT=act.getIncomingTransitions();
497                if (incT.size()==0) {
498                   icEnds.add(act);
499                   if (!fullCheck) {
500                      break;
501                   }
502                } else if (incT.size()==1) {
503                   Transition t=(Transition)incT.toArray()[0];
504                   Activity a=(Activity)((DefaultPort)t.getSource()).getParent();
505                   Set eas=XMLUtil.getEndingActivities((XMLCollectionElement)getXPDLObject());
506                   if (!eas.contains(a.getPropertyObject())) {
507                      icEnds.add(act);
508                      if (!fullCheck) {
509                         break;
510                      }
511                   }
512                }
513             } else if (!(act instanceof Start)) {
514                Set outgoingTrans=act.getNonExceptionalOutgoingTransitions();
515                if (outgoingTrans.size()==0) {
516                   icEnds.add(act);
517                   if (!fullCheck) {
518                      break;
519                   }
520                }
521                if (outgoingTrans.size()==1) {
522                   if (Utils.hasCircularTransitions(outgoingTrans)) {
523                      icEnds.add(act);
524                      if (!fullCheck) {
525                         break;
526                      }
527                   }
528                }
529             }
530          }
531       }
532
533       return icEnds;
534    }
535
536    protected void updateXMLObjectsBeforeChecking () {
537       // first update extended attributes for start and end for all processes
538
// gets all activities (processes)
539
WorkflowProcess wp=(WorkflowProcess)getPropertyObject();
540       wp.setStartDescriptions(Utils.getStartDescriptions((ProcessEditor)editor));
541       wp.setEndDescriptions(Utils.getEndDescriptions((ProcessEditor)editor));
542       // find all block activities
543
Set blockActs=workflowManager.getBlockActivities(true);
544       Iterator itBas=blockActs.iterator();
545       while (itBas.hasNext()) {
546          BlockActivity ba=(BlockActivity)itBas.next();
547          ProcessEditor bwe=ba.getImplementationEditor();
548          org.enhydra.jawe.xml.elements.Activity bap=
549             (org.enhydra.jawe.xml.elements.Activity)
550             ba.getUserObject();
551          bap.setStartDescriptions(Utils.getStartDescriptions(bwe));
552          bap.setEndDescriptions(Utils.getEndDescriptions(bwe));
553       }
554    }
555
556    /**
557     * Checks if graph conforms to the given conformance class.
558     * @return true if graph is conformant, false otherwise
559     */

560    public boolean checkGraphConformance(boolean fullCheck) {
561       PackageValidator pv=new PackageValidator(getXMLPackage(),true,true,false,false,
562                                                JaWEConfig.getInstance().getAllowUndefinedStartActivity(),
563                                                JaWEConfig.getInstance().getAllowUndefinedEndActivity(),
564                                                JaWEConfig.getInstance().getEncoding());
565       XMLCollectionElement wpOrAs=(XMLCollectionElement)getXPDLObject();
566       boolean areGraphsConformant=pv.checkGraphConformance(wpOrAs,fullCheck);
567       basicGraphConformanceErrors=pv.getBasicGraphConformanceErrors(wpOrAs);
568       graphConformanceErrors=pv.getGraphConformanceErrors(wpOrAs);
569       return areGraphsConformant;
570    }
571
572    public boolean checkLogic (boolean fullCheck) {
573       PackageValidator pv=new PackageValidator(getXMLPackage(),true,true,false,false,
574                                                JaWEConfig.getInstance().getAllowUndefinedStartActivity(),
575                                                JaWEConfig.getInstance().getAllowUndefinedEndActivity(),
576                                                JaWEConfig.getInstance().getEncoding());
577       boolean isLogical=pv.checkWorkflowProcess((WorkflowProcess)getXPDLObject(),fullCheck);
578       basicLogicError=pv.getBasicLogicError((WorkflowProcess)getXPDLObject());
579       logicErrors=pv.getLogicErrors((WorkflowProcess)getXPDLObject());
580       return isLogical;
581    }
582
583    /**
584     * Reacts upon the XML element change by setting isModified flag
585     * of PackageEditor if needed.
586     */

587    public void xmlElementChanged (XMLElement el) {
588       if (el instanceof org.enhydra.jawe.xml.elements.Activity) {
589          editor.getStatusBar().updateMessage();
590       }
591    }
592
593 }
594
Popular Tags