1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 /***
19 * <p>Title: WSMO Studio</p>
20 * <p>Description: Semantic Web Service Editor</p>
21 * <p>Copyright: Copyright (c) 2004-2006</p>
22 * <p>Company: OntoText Lab. / SIRMA </p>
23 */
24
25 package org.wsmostudio.choreography.editors;
26
27 import java.util.*;
28 import java.util.List;
29
30 import org.eclipse.jface.action.*;
31 import org.eclipse.jface.dialogs.Dialog;
32 import org.eclipse.jface.dialogs.MessageDialog;
33 import org.eclipse.jface.resource.JFaceResources;
34 import org.eclipse.jface.viewers.*;
35 import org.eclipse.swt.SWT;
36 import org.eclipse.swt.custom.*;
37 import org.eclipse.swt.events.*;
38 import org.eclipse.swt.graphics.Image;
39 import org.eclipse.swt.layout.*;
40 import org.eclipse.swt.widgets.*;
41 import org.omwg.logicalexpression.*;
42 import org.omwg.logicalexpression.terms.Term;
43 import org.omwg.ontology.Variable;
44 import org.wsmo.common.*;
45 import org.wsmo.common.exception.InvalidModelException;
46 import org.wsmo.factory.*;
47 import org.wsmo.service.choreography.Choreography;
48 import org.wsmo.service.choreography.rule.*;
49 import org.wsmo.service.rule.*;
50 import org.wsmo.wsml.ParserException;
51 import org.wsmostudio.choreography.ChoreographyPlugin;
52 import org.wsmostudio.choreography.editors.model.ChoreographyModel;
53 import org.wsmostudio.choreography.helper.Render;
54 import org.wsmostudio.runtime.*;
55 import org.wsmostudio.ui.*;
56 import org.wsmostudio.ui.views.navigator.WSMOLabelProvider;
57
58 public class RulesManagementPanel {
59
60 private Composite editorField;
61 private RuleFormEditor editorFormEditor;
62
63 private ChoreographyModel model;
64 private TreeViewer rulesList;
65 private SashForm splitter;
66
67 private Group mainPanel;
68 private MenuManager menuMgr;
69
70 public RulesManagementPanel(Composite parent, ChoreographyModel uiModel) {
71
72 this.model = uiModel;
73
74 mainPanel = new Group(parent, SWT.NONE);
75 mainPanel.setLayout(new GridLayout(1, false));
76 mainPanel.setLayoutData(new GridData(GridData.FILL_BOTH));
77 updatePanelTitle();
78
79 splitter = new SashForm(mainPanel, SWT.HORIZONTAL);
80 splitter.setLayoutData(new GridData(GridData.FILL_BOTH));
81 splitter.setLayout(new GridLayout(2, false));
82 createTable(splitter);
83 createContextMenu();
84
85 resetEditorField(model.getChoreography().getRules() == null, false);
86 splitter.setWeights(new int[] { 1, 3 });
87 }
88
89 private void createTable(Composite parent) {
90
91 rulesList = new TreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
92 rulesList.setContentProvider(new RulesContentProvider());
93 rulesList.setLabelProvider(new WSMOLabelProvider() {
94 public String getText(Object element) {
95 if (element instanceof ChoreographyRule) {
96 return getTextForRule((ChoreographyRule)element);
97 }
98 return super.getText(element);
99 }
100 public Image getImage(Object element) {
101 if (element instanceof ChoreographyRule) {
102 return iconForRule((ChoreographyRule)element);
103 }
104 return super.getImage(element);
105 }
106 });
107 rulesList.setInput(model.getChoreography());
108 rulesList.getTree().addSelectionListener(new SelectionAdapter() {
109 public void widgetSelected(SelectionEvent e) {
110 TreeItem[] selected = rulesList.getTree().getSelection();
111 if (selected == null
112 || selected.length == 0) {
113 return;
114 }
115
116 ChoreographyRule selectedRule = (ChoreographyRule)selected[0].getData();
117 if (editorFormEditor != null) {
118 if (editorFormEditor.getRule().equals(selectedRule)) {
119 return;
120 }
121 try {
122 updateEditedRule();
123 }
124 catch(Throwable error) {
125 if (false == MessageDialog.openConfirm(splitter.getShell(),
126 "Error Updating Rule",
127 "The previously edited rule could not be updated successfully:\n"
128 + error.getMessage()
129 +"\nDo you want to proceed WITHOUT updating ?")) {
130 rulesList.setSelection(new StructuredSelection(editorFormEditor.getRule()));
131 LogManager.logError(error.getMessage());
132 return;
133 }
134 }
135 rulesList.refresh(editorFormEditor.getRule(), true);
136 }
137
138 int[] sizes = splitter.getWeights();
139 editorField.dispose();
140 if (selectedRule instanceof UpdateRule) {
141 editorFormEditor = new UpdateRuleEditor(selectedRule, model);
142 editorField = editorFormEditor.initUI(splitter);
143 }
144 else if (selectedRule instanceof ChoreographyIfThen) {
145 editorFormEditor = new IfThenEditor(selectedRule, model);
146 editorField = editorFormEditor.initUI(splitter);
147 }
148 else if (selectedRule instanceof ChoreographyQuantifiedRule) {
149 editorFormEditor = new QuantRuleEditor(selectedRule, model);
150 editorField = editorFormEditor.initUI(splitter);
151 }
152 else {
153 resetEditorField(false, false);
154 }
155 splitter.layout(true);
156 splitter.setWeights(sizes);
157 splitter.redraw();
158 }
159 });
160 rulesList.getTree().setToolTipText(
161 (model.getChoreography().getRules() == null) ?
162 "No Rules container defined. Use context menu to create one!"
163 : null);
164
165 }
166
167 public void updateEditedRule() throws Exception {
168 if (editorFormEditor != null) {
169 editorFormEditor.updateRule();
170 }
171 }
172
173 private String getTextForRule(ChoreographyRule input) {
174 StringBuffer buffer = new StringBuffer();
175 TopEntity nsHolder = Utils.findTopContainer(model);
176 if (input instanceof ChoreographyIfThen) {
177 ChoreographyIfThen ifRule = (ChoreographyIfThen)input;
178 buffer.append("if (")
179 .append(ifRule.getCondition()
180 .getRestrictedLogicalExpression().toString(nsHolder))
181 .append(") then ...");
182 }
183 else if (input instanceof ChoreographyChoose) {
184 ChoreographyChoose chooseRule = (ChoreographyChoose)input;
185 buffer.append("choose {")
186 .append(varsAsString(chooseRule.listVariables()))
187 .append("} with (")
188 .append(chooseRule.getCondition()
189 .getRestrictedLogicalExpression().toString(nsHolder))
190 .append(") do ...");
191 }
192 else if (input instanceof ChoreographyForAll) {
193 ChoreographyForAll forallRule = (ChoreographyForAll)input;
194 buffer.append("forall {")
195 .append(varsAsString(forallRule.listVariables()))
196 .append("} with (")
197 .append(forallRule.getCondition()
198 .getRestrictedLogicalExpression().toString(nsHolder))
199 .append(") do ...");
200 }
201 else if (input instanceof Add) {
202 Add addRule = (Add)input;
203 buffer.append("add (")
204 .append(factsAsString(addRule.getFact(), null, nsHolder))
205 .append(')');
206 }
207 else if (input instanceof Delete) {
208 Delete deleteRule = (Delete)input;
209 buffer.append("delete (")
210 .append(factsAsString(deleteRule.getFact(), null, nsHolder))
211 .append(')');
212 }
213 else if (input instanceof Update) {
214 Update updateRule = (Update)input;
215 buffer.append("update (");
216 if (updateRule.getOldFact() != null
217 && false == updateRule.getOldFact().isEmpty()) {
218 buffer.append(factsAsString(updateRule.getFact(), updateRule.getOldFact(), nsHolder));
219 }
220 else {
221 buffer.append(factsAsString(updateRule.getFact(), null, nsHolder));
222 }
223 buffer.append(')');
224 }
225 else {
226 buffer.append(input.toString());
227 }
228 return Utils.normalizeSpaces(buffer.toString());
229 }
230
231
232 public static String factsAsString(CompoundFact newFact, CompoundFact oldFact, TopEntity nsHolder) {
233 List<CompoundFact> facts = new LinkedList<CompoundFact>();
234 facts.add(newFact);
235 if (oldFact != null) {
236 facts.add(oldFact);
237 }
238 return Render.compoundFactToWSMLString(nsHolder, facts);
239 }
240
241
242 public static String varsAsString(Set<Variable> vars) {
243 StringBuffer buffer = new StringBuffer();
244 for(Iterator<Variable> it = vars.iterator(); it.hasNext();) {
245 buffer.append('?').append(it.next().getName());
246 if (it.hasNext()) {
247 buffer.append(',').append(' ');
248 }
249 }
250
251 return buffer.toString();
252 }
253
254 private void updatePanelTitle() {
255 ChoreographyRules rules = model.getChoreography().getRules();
256 if (rules == null) {
257 mainPanel.setText("No Rules Container");
258 }
259 else {
260 mainPanel.setText("Rules - " + rules.getIdentifier().toString());
261 }
262 if (rulesList != null) {
263 rulesList.getTree().setToolTipText(
264 (rules == null) ?
265 "No Rules container defined. Use context menu to create one!"
266 : null);
267 }
268 }
269
270 public static Image iconForRule(Rule rule) {
271 String iconID = null;
272 if (rule instanceof Add) {
273 iconID = ChoreographyPlugin.ADD_RULE_ICON;
274 }
275 else if (rule instanceof Delete) {
276 iconID = ChoreographyPlugin.DELETE_RULE_ICON;
277 }
278 else if (rule instanceof Update) {
279 iconID = ChoreographyPlugin.UPDATE_RULE_ICON;
280 }
281 else if (rule instanceof ChoreographyIfThen) {
282 iconID = ChoreographyPlugin.IF_RULE_ICON;
283 }
284 else if (rule instanceof ChoreographyForAll) {
285 iconID = ChoreographyPlugin.ALL_RULE_ICON;
286 }
287 else {
288 iconID = ChoreographyPlugin.CHOOSE_RULE_ICON;
289 }
290 return JFaceResources.getImageRegistry().get(iconID);
291 }
292
293 private void createContextMenu() {
294 menuMgr = new MenuManager();
295 menuMgr.setRemoveAllWhenShown(true);
296 menuMgr.addMenuListener(new IMenuListener() {
297 public void menuAboutToShow(IMenuManager mgr) {
298 fillContextMenu(menuMgr);
299 }
300 });
301 rulesList.getTree().setMenu(menuMgr.createContextMenu(rulesList.getTree()));
302 }
303
304 private void fillContextMenu(MenuManager menuMgr) {
305
306 if (false == GUIHelper.containsCursor(rulesList.getTree())) {
307 return;
308 }
309
310 if (this.model.getChoreography().getRules() == null) {
311 menuMgr.add(new Action("Create Rules Container") {
312 public void run() {
313 handleCreateRulesContainer();
314 }
315 });
316 return;
317 }
318 final TreeItem[] sel = rulesList.getTree().getSelection();
319 boolean onASelection = sel != null
320 && sel.length > 0
321 && GUIHelper.containsCursor(sel[0].getBounds(), rulesList.getTree());
322 boolean onATransRule = onASelection
323 && sel[0].getData() instanceof ChoreographyTransitionRule;
324
325 if (onATransRule) {
326 MenuManager subMenu = new MenuManager("Add New ...");
327 initNewRulesActions(subMenu, null);
328 menuMgr.add(subMenu);
329
330 menuMgr.add(new Separator());
331
332 subMenu = new MenuManager("Insert in Selection ...");
333 initNewRulesActions(subMenu, (ChoreographyTransitionRule)sel[0].getData());
334 menuMgr.add(subMenu);
335 }
336 else {
337 if (false == onASelection) {
338 initNewRulesActions(menuMgr, null);
339 }
340 }
341
342 if (onASelection) {
343 menuMgr.add(new Separator());
344
345 menuMgr.add(new Action("Remove") {
346 public void run() {
347 handleRemoveRule((ChoreographyRule)sel[0].getData());
348 }
349 });
350 }
351 }
352
353 private void initNewRulesActions(MenuManager menuMgr,
354 final ChoreographyTransitionRule contextTransitionRule) {
355
356 if (contextTransitionRule != null) {
357 menuMgr.add(new Action("New ADD") {
358 public void run() {
359 handleNewRuleAction(getText(), contextTransitionRule);
360 }
361 });
362 menuMgr.add(new Action("New UPDATE") {
363 public void run() {
364 handleNewRuleAction(getText(), contextTransitionRule);
365 }
366 });
367 menuMgr.add(new Action("New DELETE") {
368 public void run() {
369 handleNewRuleAction(getText(), contextTransitionRule);
370 }
371 });
372 menuMgr.add(new Separator());
373 }
374
375 menuMgr.add(new Action("New IF") {
376 public void run() {
377 handleNewRuleAction(getText(), contextTransitionRule);
378 }
379 });
380 menuMgr.add(new Action("New CHOOSE") {
381 public void run() {
382 handleNewRuleAction(getText(), contextTransitionRule);
383 }
384 });
385 menuMgr.add(new Action("New FORALL") {
386 public void run() {
387 handleNewRuleAction(getText(), contextTransitionRule);
388 }
389 });
390 }
391
392 public void dispose() {
393 editorField.dispose();
394 menuMgr = null;
395 }
396
397 private void handleCreateRulesContainer() {
398 IdentifierInputDialog iDialog = new IdentifierInputDialog(
399 mainPanel.getShell(),
400 "Create Rules Container",
401 "New Rules Container Identifier (anonymous allowed) :",
402 Utils.findTopContainer(model),
403 WSMORuntime.getRuntime().getWsmoFactory(),
404 true);
405 if (iDialog.open() != Dialog.OK) {
406 return;
407 }
408 Identifier newID = iDialog.getIdentifier();
409 ChoreographyRules newRules = ChoreographyPlugin.getFactory().containers.createRules(newID);
410 model.getChoreography().setRules(newRules);
411 model.setChanged();
412 }
413
414 private void handleRemoveRule(ChoreographyRule removeRule) {
415 ChoreographyTransitionRule containerRule = findContainingSelectionRule();
416
417 int[] sizes = splitter.getWeights();
418 editorFormEditor.dispose();
419 editorFormEditor = null;
420 editorField.dispose();
421 editorField = new Composite(splitter, SWT.BORDER);
422 editorField.setLayoutData(new GridData(GridData.FILL_BOTH));
423 splitter.layout(true);
424 splitter.setWeights(sizes);
425 splitter.redraw();
426
427 if (containerRule != null) {
428 model.removeRule(removeRule, containerRule);
429 }
430 else {
431 model.removeRule(removeRule);
432 }
433 rulesList.refresh(true);
434 }
435
436 private void handleNewRuleAction(String action, ChoreographyTransitionRule containerRule) {
437 ChoreographyRule newRule = constructNewRule(action);
438 if (containerRule == null) {
439 model.addRule(newRule);
440 rulesList.refresh(true);
441 }
442 else {
443 model.addRule(newRule, containerRule);
444 rulesList.refresh(containerRule, true);
445 }
446 rulesList.setSelection(new StructuredSelection(newRule));
447 }
448
449 public void reloadRules() {
450 rulesList.refresh(true);
451 updatePanelTitle();
452 if (model.getChoreography().getRules() == null) {
453 resetEditorField(true, true);
454 }
455 else if (model.getChoreography().getRules().listRules().size() == 0) {
456 resetEditorField(false, true);
457 }
458 }
459
460 private ChoreographyRule constructNewRule(String actionName) {
461 ChoreographyFactory factory = ChoreographyPlugin.getFactory();
462 LogicalExpressionFactory leFactory = WSMORuntime.getRuntime().getLogExprFactory();
463
464 if (actionName.endsWith("ADD")) {
465 CompoundFact compoundFact = createDummyFact(leFactory, factory);
466 ChoreographyRule addRule = factory.updateRules.createAdd(compoundFact);
467 return addRule;
468 }
469 if (actionName.endsWith("UPDATE")) {
470 CompoundFact compoundFact = createDummyFact(leFactory, factory);
471 ChoreographyRule updateRule = factory.updateRules.createUpdate(compoundFact);
472 return updateRule;
473 }
474 if (actionName.endsWith("DELETE")) {
475 CompoundFact compoundFact = createDummyFact(leFactory, factory);
476 ChoreographyRule deleteRule = factory.updateRules.createDelete(compoundFact);
477 return deleteRule;
478 }
479 LogicalExpression defaultLE = null;
480 Condition condition = null;
481 try {
482 defaultLE = leFactory.createLogicalExpression("false.");
483 condition = factory.transitionRules.createConditionFromLogicalExpression(defaultLE);
484 }
485 catch(ParserException pe) {
486 LogManager.logError(pe);
487 }
488 catch(InvalidModelException ime) {
489 LogManager.logError(ime);
490 }
491
492 if (actionName.endsWith("IF")) {
493 ChoreographyRule ifRule = factory.transitionRules.createIfThen(condition, new HashSet<ChoreographyRule>());
494 return ifRule;
495 }
496 if (actionName.endsWith("CHOOSE")) {
497 ChoreographyRule chooseRule =
498 factory.transitionRules.createChoose(new HashSet<Variable>(),
499 condition,
500 new HashSet<ChoreographyRule>());
501 return chooseRule;
502 }
503 if (actionName.endsWith("FORALL")) {
504 ChoreographyRule forallRule = factory.transitionRules.createForAll(new HashSet<Variable>(),
505 condition,
506 new HashSet<ChoreographyRule>());
507 return forallRule;
508 }
509 return null;
510 }
511
512 public static CompoundFact createDummyFact(LogicalExpressionFactory leFactory,
513 ChoreographyFactory factory) {
514 Term leftOp = WSMORuntime.getRuntime().getLogExprFactory().createVariable("a");
515 Term rightOp = WSMORuntime.getRuntime().getLogExprFactory().createVariable("b");
516
517 MembershipMolecule molecule = leFactory.createMemberShipMolecule(leftOp, rightOp);
518 MoleculeFact newFact = factory.facts.createMoleculeFact();
519 newFact.addMembershipMolecule(molecule);
520 return newFact;
521 }
522
523 private ChoreographyTransitionRule findContainingSelectionRule() {
524 ChoreographyTransitionRule containerRule = null;
525 TreeItem parentItem = rulesList.getTree().getSelection()[0].getParentItem();
526 if (parentItem != null) {
527 containerRule = (ChoreographyTransitionRule)parentItem.getData();
528 }
529 return containerRule;
530 }
531
532 private void resetEditorField(boolean createLabel, boolean isShownContext) {
533 int[] sizes = null;
534 if (isShownContext) {
535 sizes = splitter.getWeights();
536 editorField.dispose();
537 }
538
539 editorFormEditor = null;
540 editorField = new Composite(splitter, SWT.BORDER);
541 editorField.setLayout(new GridLayout());
542
543 if (createLabel) {
544 Label lab = new Label(editorField, SWT.NONE);
545 lab.setText(" < No Rules container defined. Use context menu to create one! >");
546 lab.setToolTipText("No Rules container defined. Use context menu to create one!");
547 lab.setLayoutData(new GridData(GridData.FILL_BOTH));
548 lab.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
549 final MenuManager contextMgr = new MenuManager();
550 contextMgr.setRemoveAllWhenShown(true);
551 contextMgr.addMenuListener(new IMenuListener() {
552 public void menuAboutToShow(IMenuManager mgr) {
553 contextMgr.add(new Action("Create Rules Container") {
554 public void run() {
555 handleCreateRulesContainer();
556 }
557 });
558 }
559 });
560 lab.setMenu(contextMgr.createContextMenu(lab));
561 }
562
563 editorField.setLayoutData(new GridData(GridData.FILL_BOTH));
564 if (isShownContext) {
565 splitter.setWeights(sizes);
566 splitter.redraw();
567 }
568 }
569
570 class RulesContentProvider implements ITreeContentProvider {
571
572 public Object[] getChildren(Object parentElement) {
573 if (parentElement == null) {
574 return null;
575 }
576 if (parentElement instanceof ChoreographyTransitionRule) {
577 return ((ChoreographyTransitionRule)parentElement).listNestedRules().toArray();
578 }
579 return null;
580 }
581
582 public Object getParent(Object element) {
583 return null;
584 }
585
586 public boolean hasChildren(Object element) {
587 if (element instanceof ChoreographyTransitionRule) {
588 return ((ChoreographyTransitionRule)element).listNestedRules().size() > 0;
589 }
590 return false;
591 }
592
593 public Object[] getElements(Object inputElement) {
594 if (inputElement == null) {
595 return null;
596 }
597 if (inputElement instanceof Choreography) {
598 if (((Choreography)inputElement).getRules() == null) {
599 return new Object[0];
600 }
601 return ((Choreography)inputElement).getRules().listRules().toArray();
602 }
603 return null;
604 }
605
606 public void dispose() {
607 }
608
609 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
610 }
611 }
612
613
614 }
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696