1
2
3
4
5
6
7
8
9
10
11
12 package com.sri.emo.controller;
13
14 import com.jcorporate.expresso.core.controller.*;
15 import com.jcorporate.expresso.core.db.DBConnection;
16 import com.jcorporate.expresso.core.db.DBConnectionPool;
17 import com.jcorporate.expresso.core.db.DBException;
18 import com.jcorporate.expresso.core.dbobj.ValidValue;
19 import com.jcorporate.expresso.core.registry.RequestRegistry;
20 import com.sri.common.util.ObjectCombinator;
21 import com.sri.emo.dbobj.*;
22 import com.sri.emo.wizard.IWizardManager;
23 import com.sri.emo.wizard.expressoimpl.WizardController;
24 import com.sri.emo.wizard.selection.EmoSelectionWizard;
25 import com.sri.emo.wizard.selection.WizardAction;
26 import com.sri.emo.wizard.selection.management.PromptStepType;
27 import com.sri.emo.wizard.selection.management.WizardStepController;
28 import com.sri.emo.wizard.wizardgateway.ListWizards;
29 import com.sri.emo.wizard.wizardgateway.WizardGatewayController;
30
31 import java.util.*;
32
33
34 /***
35 * Provides CRUD capabilities for Wizard DBObjects. It is designed as a
36 * series of Transaction Scripts. See <a href="http://www.martinfowler.com/eaaCatalog/">
37 * Patterns of Enterprise Application Architecture</a> pattern list for
38 * more information.
39 * <p> A controller is a rough model of a finite state machine for a web application.
40 * Each state provides user interaction elements that can be rendered in a web
41 * page or other medium such as a command line app.</p>
42 *
43 * @author Mike Rimov
44 */
45 public class SelectionWizardManager extends EmoAction implements IWizardManager {
46
47 /***
48 *
49 */
50 private static final long serialVersionUID = 1L;
51
52 /***
53 * Constant for access to state: Add Wizard.
54 */
55 public static final String STATE_PROMPT_ADDWIZARD = "promptAddWizard";
56
57 /***
58 * Finishes the post to state.
59 */
60 public static final String STATE_DO_ADDWIZARD = "doAdd";
61
62 /***
63 * Finishes the edit to update state.
64 */
65 public static final String STATE_DO_EDIT = "doEdit";
66
67 /***
68 * Constant for access to state: Edit Wizard.
69 */
70 public static final String STATE_PROMPT_EDIT = "promptEdit";
71
72 /***
73 * Constant for access to state: Delete Wizard.
74 */
75 public static final String STATE_DO_DELETE = "doDelete";
76
77
78 /***
79 * Constant for access to state: Run Wizard.
80 */
81 public static final String STATE_RUNWIZARD = "runWizard";
82
83 /***
84 * synonym to serve old URLs
85 */
86 public static final String STATE_PUBLIC_LIST = "publicList";
87
88
89 /***
90 * Creates an instance of WizardManager. The Controller constructor also defines
91 * what states and parameters are officially defined by the Controller.
92 */
93 public SelectionWizardManager() {
94 State s = new State(STATE_PROMPT_ADDWIZARD, "Add Wizard");
95 addState(s);
96
97 s = new State(STATE_DO_ADDWIZARD, "Save New Wizard");
98 addState(s);
99
100 s = new State(STATE_DO_EDIT, "Save Updated Wizard");
101 s.addRequiredParameter(WizardController.WIZ_PARAMETER_ID);
102 addState(s);
103
104 s = new State(STATE_PROMPT_EDIT, "Prompt Edit Wizard");
105 s.addRequiredParameter(WizardController.WIZ_PARAMETER_ID);
106 addState(s);
107
108
109 s = new State(STATE_RUNWIZARD, "Run Wizard");
110 s.addRequiredParameter(WizardController.WIZ_PARAMETER_ID);
111 addState(s);
112
113 s = new State(STATE_PUBLIC_LIST, "Public List");
114 addState(s);
115
116 setInitialState(STATE_PROMPT_ADDWIZARD);
117 setSchema(com.sri.emo.EmoSchema.class);
118 }
119
120 /***
121 * Override of Controller.getTitle() to provide a meaningful name to this
122 * controller.
123 *
124 * @return java.lang.String
125 */
126 public String getTitle() {
127 return "Wizard Manager";
128 }
129
130 /***
131 * Runs the Add Wizard Prompt state.
132 *
133 * @param request The <code>ControllerRequest</code> object handed to us by the framework.
134 * The ControllerRequest contains all the parameters such as web parameters, user
135 * security credentials and user locale
136 * @param response The <code>ControllerResponse</code> object handed to us by the framework.
137 * The ControllerResponse will be populated with the Inputs/Outputs/Transitions/Blocks
138 * for ths sytem.
139 * @throws ControllerException upon error
140 * @throws NonHandleableException upon fatal error
141 */
142 protected void runPromptAddWizardState(final ControllerRequest request,
143 final ControllerResponse response) throws ControllerException,
144 NonHandleableException {
145 response.setTitle("Add Wizard");
146
147 Hashtable cache = response.getFormCache();
148
149 String value = (String) cache.get("title");
150 if (value == null) {
151 value = "";
152 }
153 Input i = new Input("title", "Name");
154 i.setDefaultValue(value);
155 response.add(i);
156 value = (String) cache.get("wizardClass");
157 if (value == null) {
158 value = EmoSelectionWizard.class.getName();
159 }
160
161 i = new Input("wizardClass", "Wizard Class");
162 i.setDefaultValue(value);
163
164 response.add(i);
165 value = (String) cache.get("summary");
166 if (value == null) {
167 value = "";
168 }
169 i = new Input("summary", "Summary");
170 i.setDefaultValue(value);
171 response.add(i);
172
173 Transition save = new Transition("save", "save", getClass(), STATE_DO_ADDWIZARD);
174 response.add(save);
175 }
176
177 /***
178 * Runs the complete update state.
179 *
180 * @param request The <code>ControllerRequest</code> object handed to us by the framework.
181 * The ControllerRequest contains all the parameters such as web parameters, user
182 * security credentials and user locale
183 * @param response The <code>ControllerResponse</code> object handed to us by the framework.
184 * The ControllerResponse will be populated with the Inputs/Outputs/Transitions/Blocks
185 * for ths sytem.
186 * @throws ControllerException upon error
187 * @throws NonHandleableException upon fatal error
188 */
189 protected void runDoEditState(final ControllerRequest request,
190 final ControllerResponse response) throws ControllerException,
191 NonHandleableException {
192 try {
193 ErrorCollection ec = request.getErrorCollection();
194
195 if (ec == null) {
196 ec = new ErrorCollection();
197 }
198
199 WizDefinition wizdef = getWizDef(request);
200
201
202
203
204 verifyWizardParameters(request, ec, wizdef);
205 if (wizdef.getPageDefinitions().size() == 0) {
206 ec.addError("You need to have one or more steps defined. " +
207 "Click 'add step' below to add a step.");
208 }
209 List pertinentSteps = wizdef.getPertinentDecisionSteps();
210 ObjectCombinator combinator = buildObjectCombinator(pertinentSteps);
211
212
213 validateDecisionMatrix(request, ec, combinator);
214
215 if (ec.getErrorCount() > 0) {
216 if (getLogger().isDebugEnabled()) {
217 getLogger().debug("Errors in error collection: " + ec.getErrorCount()
218 + " errors.");
219 }
220 response.saveErrors(ec);
221 response.setFormCache();
222 transition(STATE_PROMPT_EDIT, request, response);
223 return;
224 }
225
226 DBConnection transaction = DBConnectionPool.getInstance(request.
227 getDataContext()).getConnection("Wizard Update");
228 try {
229 transaction.setAutoCommit(false);
230 wizdef.setConnection(transaction);
231 wizdef.update(true);
232 WizDecisionSet decisionSet = new WizDecisionSet(transaction, RequestRegistry.getUser().getUid());
233
234
235
236
237
238 /***
239 * @todo Optimize the writing behavior here with some sort
240 * of unit of work.
241 */
242
243 decisionSet.setWizardId(wizdef.getId());
244 decisionSet.deleteAll(true);
245 decisionSet.clear();
246 decisionSet.setWizardId(wizdef.getId());
247
248
249
250 int counter = 0;
251 for (Iterator i = combinator.iterator(); i.hasNext();) {
252 decisionSet.clear();
253 decisionSet.setWizardId(wizdef.getId());
254 String param = "exId" + counter;
255 counter++;
256 String paramValue = request.getParameter(param);
257 if (paramValue == null || paramValue.length() == 0) {
258 i.next();
259 continue;
260 }
261
262 int parameterValue = Integer.parseInt(paramValue);
263
264 decisionSet.setDecisionResult(parameterValue);
265 decisionSet.setWizardId(wizdef.getId());
266 decisionSet.add();
267
268 ValidValue[] vv = (ValidValue[]) i.next();
269 int[] stepIds = new int[vv.length];
270 String pickListIds[] = new String[vv.length];
271 for (int j = 0; j < vv.length; j++) {
272 WizStep oneStep = (WizStep) pertinentSteps.get(j);
273 stepIds[j] = oneStep.getFieldInt(WizStep.FLD_ID);
274 pickListIds[j] = vv[j].getKey();
275 }
276
277 decisionSet.addDecisionEntity(stepIds, pickListIds);
278 }
279
280 transaction.commit();
281 } catch (DBException ex) {
282 transaction.rollback();
283 throw new ControllerException("Database Access Error", ex);
284 } finally {
285 transaction.release();
286 }
287
288 Transition t = new Transition("nextpage", "nextpage", WizardGatewayController.class,
289 ListWizards.STATE_NAME);
290
291 t.addParam(WizardController.WIZ_PARAMETER_ID, wizdef.getId());
292
293 t.redirectTransition(request, response);
294 } catch (DBException ex) {
295 throw new ControllerException("Error accessing wizard definition", ex);
296 }
297 }
298
299 /***
300 * Retrieve the wizard definition based upon the parameters in the controller request.
301 *
302 * @param request ControllerRequest the ControllerRequest object.
303 * @return WizDefinition the defined wizard definition.
304 * @throws DBException if we are unable to locate it in the database.
305 */
306 private WizDefinition getWizDef(final ControllerRequest request) throws DBException {
307 WizDefinition wizdef = new WizDefinition();
308 wizdef.setId(request.getParameter(WizardController.WIZ_PARAMETER_ID));
309 wizdef.retrieve();
310 return wizdef;
311 }
312
313 /***
314 * Provides some validation against the decision matrix values entered
315 * by "DoEditWizard"
316 *
317 * @param request ControllerRequest The ControllerRequest object
318 * @param ec ErrorCollection the ErrorCollection
319 * @param combinator ObjectCombinator the ObjectCombinator for the wizard.
320 * @throws DBException upon error.
321 */
322 private void validateDecisionMatrix(final ControllerRequest request,
323 final ErrorCollection ec,
324 final ObjectCombinator combinator) throws DBException {
325
326 int counter = 0;
327 for (Iterator i = combinator.iterator(); i.hasNext(); i.next()) {
328 String param = "exId" + counter;
329 String paramValue = request.getParameter(param);
330 if (paramValue == null || paramValue.length() == 0) {
331 continue;
332 } else {
333 try {
334 int paramInteger = Integer.parseInt(paramValue);
335 Node node = new Node();
336 node.setNodeId(Integer.toString(paramInteger));
337 if (!node.find()) {
338 ec.addError("Value for Decision Matrix Cell #"
339 + counter
340 + " has no corresponding example id. Please "
341 + "double-check the value you entered");
342 }
343 } catch (NumberFormatException ex) {
344 ec.addError("Value for Decision Matrix Cell #"
345 + counter
346 + " needs to be a number");
347 }
348 }
349 counter++;
350 }
351 }
352
353
354 /***
355 * Runs the Complete Add Wizard state.
356 *
357 * @param request The <code>ControllerRequest</code> object handed to us by the framework.
358 * The ControllerRequest contains all the parameters such as web parameters, user
359 * security credentials and user locale
360 * @param response The <code>ControllerResponse</code> object handed to us by the framework.
361 * The ControllerResponse will be populated with the Inputs/Outputs/Transitions/Blocks
362 * for ths sytem.
363 * @throws ControllerException upon error
364 * @throws NonHandleableException upon fatal error
365 */
366 protected void runDoAddState(final ControllerRequest request,
367 final ControllerResponse response) throws ControllerException,
368 NonHandleableException {
369 try {
370 ErrorCollection ec = request.getErrorCollection();
371
372 if (ec == null) {
373 ec = new ErrorCollection();
374 }
375
376 WizDefinition wizdef = new WizDefinition();
377 wizdef.setFieldsWithDefaults();
378 verifyWizardParameters(request, ec, wizdef);
379
380 if (ec.getErrorCount() > 0) {
381 if (getLogger().isDebugEnabled()) {
382 getLogger().debug("Errors in error collection: " + ec.getErrorCount()
383 + " errors.");
384 }
385 response.saveErrors(ec);
386 response.setFormCache();
387 transition(STATE_PROMPT_ADDWIZARD, request, response);
388 return;
389 }
390
391
392
393
394 DBConnection trx = DBConnectionPool.getInstance(request.getDataContext())
395 .getConnection("EMO Add Wizard");
396 try {
397 trx.setAutoCommit(false);
398
399 wizdef.setConnection(trx);
400 wizdef.add();
401
402
403 WizStep welcomeStep = new WizStep(trx);
404 welcomeStep.setField(WizStep.FLD_TITLE, "Welcome");
405 welcomeStep.setField(WizStep.FLD_DIRECTIVE, "Click the 'next' button.");
406 welcomeStep.setWizId(wizdef.getId());
407 welcomeStep.setField(WizStep.FLD_STEP_TYPE, PromptStepType.INSTRUCTIONS_ONLY);
408 welcomeStep.setField(WizStep.FLD_HELPTEXT, "A short interview will follow.");
409 welcomeStep.add();
410
411 trx.commit();
412 } catch (Exception e) {
413 trx.rollback();
414 getLogger().error("Error writing transaction", e);
415 throw new ControllerException("Error writing transaction", e);
416 } finally {
417 trx.release();
418 }
419
420 Transition t = new Transition("nextpage", "nextpage", getClass(), STATE_PROMPT_EDIT);
421 t.addParam(WizardController.WIZ_PARAMETER_ID, wizdef.getId());
422
423 t.redirectTransition(request, response);
424 } catch (DBException ex) {
425 throw new ControllerException("Error accessing wizard definition", ex);
426 }
427 }
428
429 /***
430 * Checks the parameters for add and edit wizard state pertaining to
431 * the wizard definition itself.
432 *
433 * @param request The <code>CntrollerRequest</code> object.
434 * @param ec The error collection to fill with errors if there are
435 * issues.
436 * @param wizdef the Wizard definition object to populate with values for
437 * title, summary, etc if the items are ok.
438 * @throws DBException upon database setField error.
439 */
440 protected void verifyWizardParameters(final ControllerRequest request,
441 final ErrorCollection ec,
442 final WizDefinition wizdef) throws
443 DBException {
444 String value = request.getParameter("title");
445 try {
446 if (value == null || value.length() == 0) {
447 ec.addError("You must have a title for your wizard.");
448 } else {
449 wizdef.checkField(WizDefinition.FLD_NAME, value);
450 wizdef.setField(WizDefinition.FLD_NAME, value);
451 }
452 } catch (DBException ex) {
453 getLogger().error("Error validating field: " + WizDefinition.FLD_NAME, ex);
454 ec.addError(ex.getMessage());
455 }
456
457 value = request.getParameter("wizardClass");
458 try {
459 wizdef.checkField(WizDefinition.FLD_WIZARD, value);
460 wizdef.setField(WizDefinition.FLD_WIZARD, value);
461 } catch (DBException ex) {
462 getLogger().error("Error validating field: " + WizDefinition.FLD_WIZARD, ex);
463 ec.addError(ex.getMessage());
464 }
465
466 value = request.getParameter("summary");
467 if (value != null) {
468 wizdef.setField(WizDefinition.FLD_SUMMARY, value);
469 }
470 }
471
472
473 /***
474 * Runs the Delete Wizard state.
475 *
476 * @param request The <code>ControllerRequest</code> object handed to us by the framework.
477 * The ControllerRequest contains all the parameters such as web parameters, user
478 * security credentials and user locale
479 * @param response The <code>ControllerResponse</code> object handed to us by the framework.
480 * The ControllerResponse will be populated with the Inputs/Outputs/Transitions/Blocks
481 * for ths sytem.
482 * @throws ControllerException upon error
483 * @throws NonHandleableException upon fatal error
484 */
485 protected void runDoDeleteState(final ControllerRequest request,
486 final ControllerResponse response) throws ControllerException,
487 NonHandleableException {
488 try {
489 WizDefinition wizdef = getWizDef(request);
490 wizdef.delete(true);
491 Transition next = new Transition("next", "next", WizardGatewayController.class, ListWizards.STATE_NAME);
492 next.redirectTransition(request, response);
493 } catch (DBException ex) {
494 throw new ControllerException("Database error deleting wizard.", ex);
495 }
496 }
497
498 /***
499 * Runs the Prompt Delete Wizard state.
500 *
501 * @param request The <code>ControllerRequest</code> object handed to us by the framework.
502 * The ControllerRequest contains all the parameters such as web parameters, user
503 * security credentials and user locale
504 * @param response The <code>ControllerResponse</code> object handed to us by the framework.
505 * The ControllerResponse will be populated with the Inputs/Outputs/Transitions/Blocks
506 * for ths sytem.
507 * @throws ControllerException upon error
508 * @throws NonHandleableException upon fatal error
509 */
510 protected void runPromptDeleteState(final ControllerRequest request,
511 final ControllerResponse response) throws ControllerException,
512 NonHandleableException {
513
514 try {
515 response.setTitle("Confirm Delete Wizard");
516 WizDefinition wizdef = getWizDef(request);
517 response.add(new Output("prompt", wizdef.getWizName()));
518
519 Transition yes = new Transition("yes", "yes", getClass(), STATE_DO_DELETE);
520 yes.addParam(WizardController.WIZ_PARAMETER_ID, request.getParameter(WizardController.WIZ_PARAMETER_ID));
521 response.add(yes);
522 Transition no = new Transition("no", "no", WizardGatewayController.class, ListWizards.STATE_NAME);
523 response.add(no);
524 } catch (DBException ex) {
525 throw new ControllerException("Database Error retrieving wizard.", ex);
526 }
527 }
528
529
530 /***
531 * Runs the Edit Wizard state.
532 *
533 * @param request The <code>ControllerRequest</code> object handed to us by the framework.
534 * The ControllerRequest contains all the parameters such as web parameters, user
535 * security credentials and user locale
536 * @param response The <code>ControllerResponse</code> object handed to us by the framework.
537 * The ControllerResponse will be populated with the Inputs/Outputs/Transitions/Blocks
538 * for ths sytem.
539 * @throws ControllerException upon error
540 * @throws NonHandleableException upon fatal error
541 */
542 protected void runPromptEditState(final ControllerRequest request,
543 final ControllerResponse response) throws ControllerException,
544 NonHandleableException {
545 try {
546 WizDefinition wizdef = getWizDef(request);
547 response.setTitle("'" + wizdef.getWizName() + "' Wizard");
548 Hashtable cache = response.getFormCache();
549
550 String value = (String) cache.get("title");
551 if (value == null) {
552 value = wizdef.getWizName();
553 }
554 Input input = new Input("title", "Name");
555 input.setDefaultValue(value);
556 response.add(input);
557 value = (String) cache.get("wizardClass");
558 if (value == null) {
559 value = wizdef.getWizardClass();
560 }
561
562 input = new Input("wizardClass", "Wizard Class");
563 input.setDefaultValue(value);
564 response.add(input);
565 value = (String) cache.get("summary");
566 if (value == null) {
567 value = wizdef.getSummaryRaw();
568 }
569 input = new Input("summary", "Summary");
570 input.setDefaultValue(value);
571 response.add(input);
572
573 Block wizSteps = new Block("steps");
574 buildWizardSteps(request, wizSteps, wizdef);
575 response.add(wizSteps);
576
577 Transition addStep = new Transition("add", "add step", WizardStepController.class,
578 PromptStepType.STATE_NAME);
579 addStep.addParam(WizStep.FLD_WIZID, wizdef.getId());
580 response.add(addStep);
581
582 Block decisionMatrix = new Block("decisionMatrix");
583 buildDecisionMatrix(request, response, decisionMatrix, wizdef);
584 response.add(decisionMatrix);
585
586 Transition save = new Transition("save", "save", getClass(), SelectionWizardManager.STATE_DO_EDIT);
587 save.addParam(WizardController.WIZ_PARAMETER_ID, wizdef.getId());
588 response.add(save);
589
590 Transition run = getRunTrans(wizdef.getId());
591 response.add(run);
592 } catch (DBException ex) {
593 throw new ControllerException("Error accessing wizard definition", ex);
594 }
595 }
596
597 /***
598 * Builds the steps for the current wizard.
599 *
600 * @param request the ControllerRequest object
601 * @param steps the block to populate with the steps.
602 * @param currentWizard the current wizard to build the steps for.
603 * @throws DBException upon database access error
604 * @throws ControllerException upon ControllerElement related error
605 */
606 protected void buildWizardSteps(final ControllerRequest request,
607 final Block steps,
608 final WizDefinition currentWizard) throws DBException, ControllerException {
609 List pages = currentWizard.getPageDefinitions();
610 int counter = 1;
611 for (Iterator iterator = pages.iterator(); iterator.hasNext();) {
612 WizStep onestep = (WizStep) iterator.next();
613 Block oneRow = new Block("oneRow" + counter);
614 steps.add(oneRow);
615 oneRow.add(new Output("index", Integer.toString(counter)));
616
617 Transition delete = new Transition("delete", "delete", WizardStepController.class,
618 WizardStepController.STATE_PROMPT_DELETE);
619 delete.addParam(WizStep.FLD_ID, onestep.getId());
620 delete.addParam(WizardController.WIZ_PARAMETER_ID, currentWizard.getId());
621 oneRow.add(delete);
622
623 Transition edit = new Transition("edit", onestep.getTitle(), WizardStepController.class,
624 WizardStepController.STATE_PROMPT_EDIT);
625 edit.addParam(WizStep.FLD_ID, onestep.getId());
626 edit.addParam(WizStep.FLD_WIZID, onestep.getWizId());
627 oneRow.add(edit);
628
629
630 switch (onestep.getStepType()) {
631 case PromptStepType.CUSTOM_PICKLIST: {
632
633 /***@todo Set up parameters for custom picklist */
634
635
636
637
638
639 break;
640 }
641
642 case PromptStepType.INSTANCE_PICKLIST: {
643 String nodeId = onestep.getStepAttribute(StepAttributes.ATTRIBUTE_INSTANCE_ID);
644 String attributeId = onestep.getStepAttribute(StepAttributes.ATTRIBUTE_INSTANCE_FIELD);
645 Transition editMenu = new Transition(onestep.getMenuAttribLabel() + ":" + nodeId, NodeAction.class,
646 NodeAction.PROMPT_EDIT_ATTRIB);
647 editMenu.addParam(Node.NODE_ID, nodeId);
648
649 Part part = new Part();
650 part.setPartId(attributeId);
651 part.retrieve();
652
653 editMenu.addParam(Attribute.ATTRIBUTE_TYPE, part.getPartType());
654 editMenu.setName("picklist");
655 oneRow.add(editMenu);
656 break;
657 }
658
659 case PromptStepType.MODEL_PICKLIST: {
660 Part part = PartsFactory.getPart(
661 onestep.getStepAttribute(StepAttributes.ATTRIBUTE_MODEL_FIELD));
662 if (part != null && part.hasPicklist()) {
663 Transition editMenu = new Transition(part.getPartLabel(), PicklistAction.class,
664 PicklistAction.PROMPT_LIST);
665 editMenu.addParam(PickList.NODE_TYPE, part.getParentType());
666 editMenu.addParam(PickList.ATTRIBUTE_TYPE, part.getPartType());
667 editMenu.setName("picklist");
668 oneRow.add(editMenu);
669 break;
670 }
671 }
672 }
673
674 if (counter != 1) {
675 Transition up = new Transition("up", "up",
676 WizardStepController.class, WizardStepController.STATE_ORDERUP);
677 up.addParam(WizStep.FLD_ID, onestep.getId());
678 up.addParam(WizardController.WIZ_PARAMETER_ID, currentWizard.getId());
679 oneRow.add(up);
680 }
681
682 if (iterator.hasNext()) {
683 Transition down = new Transition("down", "down",
684 WizardStepController.class,
685 WizardStepController.STATE_ORDERDOWN);
686 down.addParam(WizStep.FLD_ID, onestep.getId());
687 down.addParam(WizardController.WIZ_PARAMETER_ID, currentWizard.getId());
688 oneRow.add(down);
689 }
690 counter++;
691 }
692 }
693
694 /***
695 * Builds the decision matrix for the current wizard.
696 *
697 * @param request the ControllerRequest object.
698 * @param response the ControllerResponse object.
699 * @param matrix the block to populate with the steps.
700 * @param currentWizard the current wizard to build the steps for.
701 * @throws DBException upon database access error
702 * @throws ControllerException upon ControllerElement related error
703 */
704 protected void buildDecisionMatrix(final ControllerRequest request,
705 final ControllerResponse response,
706 final Block matrix,
707 final WizDefinition currentWizard) throws DBException, ControllerException {
708 List pertinentSteps = currentWizard.getPertinentDecisionSteps();
709
710 if (pertinentSteps.size() == 0) {
711
712 return;
713 }
714
715 Block headerRow = new Block("header");
716 headerRow.add(new Output("Cell #"));
717 for (int i = 0; i < pertinentSteps.size(); i++) {
718 WizStep oneStep = (WizStep) pertinentSteps.get(i);
719 headerRow.add(new Output(oneStep.getMenuAttribLabel()));
720 }
721
722 headerRow.add(new Output("Prototype ID"));
723 Output titles = new Output("Prototype Title");
724 titles.setAttribute("SubTitle", "(updates after save)");
725 headerRow.add(titles);
726 matrix.add(headerRow);
727
728 ObjectCombinator combinator = buildObjectCombinator(pertinentSteps);
729 Block items = new Block("items");
730 matrix.add(items);
731 int counter = 0;
732 DecisionMatrix decisionMatrix = new DecisionMatrix(currentWizard.getId());
733
734 for (Iterator i = combinator.iterator(); i.hasNext();) {
735 Block oneRow = new Block("Row" + counter);
736 items.add(oneRow);
737 ValidValue[] pickList = (ValidValue[]) i.next();
738 Map idToVVMap = new HashMap(pickList.length);
739 oneRow.add(new Output("IterationId", Integer.toString(counter) + ")"));
740 for (int j = 0; j < pickList.length; j++) {
741 ValidValue onePick = pickList[j];
742 WizStep oneStep = (WizStep) pertinentSteps.get(j);
743 idToVVMap.put(new Integer(oneStep.getFieldInt(WizStep.FLD_ID)), new Integer(onePick.getKey()));
744 Output o = new Output("item" + j, combinator.getRowIndex(i, j) + ") "
745 + onePick.getDescription());
746
747 oneRow.add(o);
748 }
749
750 Input nodeVal = new Input("exId" + counter, "Example Id");
751 String value = response.getFormCache("exId" + counter);
752 boolean valueFound = false;
753 if (value == null || value.length() == 0) {
754 WizDecisionSet decisionSet = decisionMatrix.getDecision(idToVVMap);
755 if (decisionSet != null) {
756 valueFound = true;
757 nodeVal.setDefaultValue(decisionSet.getField(WizDecisionSet.FLD_DECISIONRESULT));
758 } else {
759 valueFound = true;
760 nodeVal.setDefaultValue("");
761 }
762 } else {
763 nodeVal.setDefaultValue(value);
764 WizDecisionSet set = new WizDecisionSet();
765 try {
766 int valueInt = Integer.parseInt(value);
767 set.setWizardId(currentWizard.getId());
768 set.setDecisionResult(valueInt);
769 if (set.find()) {
770 if (value.equals(set.getDecisionResult())) {
771 valueFound = true;
772 }
773 } else {
774 Output o = new Output("nodeLabel", "**[Error: No Such Node]**");
775 o.setAttribute("error", "y");
776 nodeVal.addNested(o);
777 }
778 } catch (NumberFormatException ex1) {
779 valueFound = false;
780 }
781 }
782
783 oneRow.add(nodeVal);
784
785
786
787
788
789
790
791 if ((nodeVal.getDefaultValue() != null && nodeVal.getDefaultValue().length() > 0)
792 && valueFound) {
793
794 Node node = new Node(request);
795 node.setNodeId(nodeVal.getDefaultValue());
796 try {
797 node.retrieve();
798 nodeVal.addNested(new Output("nodeLabel", node.getNodeTitle()));
799 } catch (DBException ex) {
800 Output o = new Output("nodeLabel", "**[Error: No Such Node]**");
801 o.setAttribute("error", "y");
802 nodeVal.addNested(o);
803 }
804 }
805 counter++;
806 }
807 }
808
809 /***
810 * Constructs an object combinator given a list of wizard steps that
811 * are pertinent to the current wizard.
812 *
813 * @param pertinentSteps List A list of WizSteps.
814 * @return ObjectCombinator constructed ObjectCombinator
815 */
816 private ObjectCombinator buildObjectCombinator(final List pertinentSteps) {
817 ValidValue[][] allPossibleValidValues = new ValidValue[pertinentSteps.size()][];
818 for (int i = 0; i < pertinentSteps.size(); i++) {
819 WizStep oneStep = (WizStep) pertinentSteps.get(i);
820 allPossibleValidValues[i] = oneStep.getMenuItems();
821 }
822
823 return new ObjectCombinator(allPossibleValidValues, ValidValue.class);
824 }
825
826 /***
827 * Runs the Run Wizard state.
828 *
829 * @param request The <code>ControllerRequest</code> object handed to us by the framework.
830 * The ControllerRequest contains all the parameters such as web parameters, user
831 * security credentials and user locale
832 * @param response The <code>ControllerResponse</code> object handed to us by the framework.
833 * The ControllerResponse will be populated with the Inputs/Outputs/Transitions/Blocks
834 * for ths sytem.
835 * @throws ControllerException upon error
836 * @throws NonHandleableException upon fatal error
837 */
838 protected void runRunWizardState(final ControllerRequest request,
839 final ControllerResponse response) throws ControllerException,
840 NonHandleableException {
841
842 String id = request.getParameter(WizardController.WIZ_PARAMETER_ID);
843 Transition t = getRunTrans(id);
844 t.redirectTransition(request, response);
845 }
846
847 /***
848 * synonym for wizard gateway 'list wizards'
849 *
850 * @param request The <code>ControllerRequest</code> object handed to us by the framework.
851 * The ControllerRequest contains all the parameters such as web parameters, user
852 * security credentials and user locale
853 * @param response The <code>ControllerResponse</code> object handed to us by the framework.
854 * The ControllerResponse will be populated with the Inputs/Outputs/Transitions/Blocks
855 * for ths sytem.
856 * @throws ControllerException upon error
857 * @throws NonHandleableException upon fatal error
858 */
859 protected void runPublicListState(final ControllerRequest request,
860 final ControllerResponse response) throws ControllerException,
861 NonHandleableException {
862 Transition t = new Transition("", WizardGatewayController.class, ListWizards.STATE_NAME);
863 t.redirectTransition(request, response);
864 }
865
866 private Transition getRunTrans(final String id) {
867 Transition t = new Transition("run", WizardAction.class, WizardAction.STATE_BEGIN);
868 t.addParam(WizardController.WIZ_PARAMETER_ID, id);
869 return t;
870 }
871
872
873 /***
874 * Runs the wizard that the manager is associated with.
875 *
876 * @param wizard WizDefinition
877 * @param request ExpressoRequest
878 * @param response ExpressoResponse
879 * @throws ControllerException
880 */
881 public void run(final WizDefinition wizard, final ExpressoRequest request, final ExpressoResponse response) throws
882 ControllerException {
883 try {
884 Transition runTransition = getRunTrans(wizard.getId());
885 runTransition.redirectTransition(request, response);
886 } catch (DBException ex) {
887 throw new ControllerException("Error processing run transition.", ex);
888 }
889 }
890
891 /***
892 * Begins an 'add' end-user transaction to create a new wizard.
893 *
894 * @param request ExpressoRequest the request object.
895 * @param response ExpressoResponse the response object.
896 * @throws ControllerException
897 */
898 public void add(final ExpressoRequest request, final ExpressoResponse response) throws ControllerException {
899 Transition t = new Transition(STATE_PROMPT_ADDWIZARD, this);
900 t.redirectTransition(request, response);
901 }
902
903 /***
904 * Begins an 'edit' end-user transaction to edit an existing wizard.
905 *
906 * @param wizard The WizardDefinition to edit.
907 * @param request ExpressoRequest the request object.
908 * @param response ExpressoResponse the response object.
909 * @throws ControllerException upon error.
910 */
911 public void edit(final WizDefinition wizard, final ExpressoRequest request,
912 final ExpressoResponse response) throws ControllerException {
913
914 Transition t = new Transition(STATE_PROMPT_EDIT, this);
915 try {
916 t.addParam(WizardController.WIZ_PARAMETER_ID, wizard.getId());
917 } catch (DBException ex) {
918 throw new ControllerException("Error querying object for id.", ex);
919 }
920 t.redirectTransition(request, response);
921 }
922 }