1
2
3
4
5
6
7
8
9
10 package com.sri.emo.dbobj;
11
12 import com.jcorporate.expresso.core.controller.Controller;
13 import com.jcorporate.expresso.core.controller.ControllerException;
14 import com.jcorporate.expresso.core.controller.Transition;
15 import com.jcorporate.expresso.core.dataobjects.DataObject;
16 import com.jcorporate.expresso.core.dataobjects.DataObjectFactory;
17 import com.jcorporate.expresso.core.dataobjects.jdbc.JDBCDataObject;
18 import com.jcorporate.expresso.core.db.DBConnection;
19 import com.jcorporate.expresso.core.db.DBException;
20 import com.jcorporate.expresso.core.db.exception.DBRecordNotFoundException;
21 import com.jcorporate.expresso.core.dbobj.DBField;
22 import com.jcorporate.expresso.core.dbobj.RowSecuredDBObject;
23 import com.jcorporate.expresso.core.dbobj.ValidValue;
24 import com.jcorporate.expresso.core.misc.ConfigManager;
25 import com.jcorporate.expresso.core.security.filters.AllowedHtmlPlusURLFilter;
26 import com.jcorporate.expresso.core.security.filters.Filter;
27 import com.jcorporate.expresso.core.security.filters.RawFilter;
28 import com.sri.emo.controller.SelectionWizardManager;
29 import com.sri.emo.wizard.expressoimpl.WizardController;
30 import com.sri.emo.wizard.persistence.AdditionalInfo;
31 import com.sri.emo.wizard.selection.management.PromptStepType;
32
33 import java.util.ArrayList;
34 import java.util.List;
35
36 /***
37 * Definition of an Emo Wizard.
38 * <p>DataObjects provide the low-level Object Relational
39 * mapping between these objects
40 * and a JDBC backend.</p>
41 */
42 public class WizDefinition extends RowSecuredDBObject implements IViewable {
43
44
45 /***
46 *
47 */
48 private static final long serialVersionUID = 1L;
49
50 /***
51 * Public constant for access to field
52 * "Item ID".
53 */
54 public static final String FLD_ID = "Id";
55
56 /***
57 * Public constant for access to field
58 * "Name".
59 */
60 public static final String FLD_NAME = "Name";
61
62 /***
63 * Public constant for access to field
64 * "wizard class".
65 */
66 public static final String FLD_WIZARD = "Wizard";
67
68 /***
69 * Public constant for access to field
70 * "Factory".
71 */
72 public static final String FLD_FACTORY = "Factory";
73
74 /***
75 * Public constant for access to field
76 * "Bean".
77 */
78 public static final String FLD_SUMMARY = "Summary";
79
80 /***
81 * Table name.
82 */
83 public static final String TABLE_NAME = "EMOWIZDEF";
84
85 /***
86 * Name of the controller.
87 */
88 public static final String FLD_CONTROLLER = "Controller";
89
90
91 /***
92 * The classname of the contorller for adding.
93 */
94 public static final String FLD_EDITOR_CONTROLLER = "EditorController";
95
96
97 /***
98 * Field that is the classname of any 1-1 mapping database object
99 * that provides additional information for this wizard.
100 */
101 public static final String FLD_ADDITIONAL_INFO = "AdditionalInfo";
102
103 /***
104 * The default controller for editing a wizard.
105 */
106 public static final String DEFAULT_EDITING_CONTROLLER = SelectionWizardManager.class.getName();
107
108
109 /***
110 * For many scenarios, it is worthwhile to bind an instance of the peer data
111 * object here. Examples are for add and update items, etc.
112 */
113 private JDBCDataObject peerDataObject = null;
114
115 /***
116 * Creates an instance of WizDefinition.
117 * before using.
118 *
119 * @throws DBException upon initialization exception.
120 * @see com.jcorporate.expresso.core.dbobj.SecuredDBObject#SecuredDBObject
121 */
122 public WizDefinition() throws DBException {
123 }
124
125 /***
126 * Creates an instance of WizDefinition that uses
127 * an already grabbed DBConnection object. This is for use
128 * inside transactions. <p>Example: <code><pre>
129 * DBConnection oneConnection = DBConnectionPool
130 * .getInstance("default").getConnection();
131 * oneConnection.setAutoCommit(false);
132 * WizDefinition myObj = new WizDefinition(oneConnection);
133 * //Set fields here....
134 * myObj.add();
135 * myObj.clear();
136 * //more set fields
137 * myObj.add();
138 * //Commit the transaction
139 * oneConnection.commit();
140 * oneConnection.release();
141 * </pre></code>
142 * </p>
143 *
144 * @param dbConnection com.jcorporate.expresso.core.db.DBConnection
145 * @param uid the user id
146 * @throws DBException upon construction error
147 */
148 public WizDefinition(final DBConnection dbConnection, final int uid) throws DBException {
149 super(dbConnection, uid);
150 }
151
152
153
154
155 public WizDefinition(final DBConnection connection) throws DBException {
156 super(connection);
157 }
158
159
160 /***
161 * Returns the managing contorller
162 *
163 * @return Controller
164 * @throws DBException
165 * @throws ControllerException
166 */
167 public Controller getManagingController() throws DBException, ControllerException {
168 String controllerClassName = this.getField(FLD_EDITOR_CONTROLLER);
169 if (controllerClassName == null || controllerClassName.length() == 0) {
170 controllerClassName = DEFAULT_EDITING_CONTROLLER;
171 }
172
173 return ConfigManager.getControllerFactory().getController(controllerClassName);
174 }
175
176
177 /***
178 * Retrieve the controller to 'run' the wizard.
179 *
180 * @return Controller
181 * @throws DBException
182 * @throws ControllerException
183 */
184 public Controller getRunningController() throws DBException, ControllerException {
185 String controllerClassName = this.getField(FLD_WIZARD);
186 if (controllerClassName == null || controllerClassName.length() == 0) {
187 controllerClassName = DEFAULT_EDITING_CONTROLLER;
188 }
189
190 return ConfigManager.getControllerFactory().getController(controllerClassName);
191
192 }
193
194 /***
195 * Retrieves all page definitions associated with this wizard definition.
196 * <em>Only useful for Selection Wizards</em>
197 *
198 * @return List of WizStep objects.
199 * @throws DBException upon error.
200 * @todo Refactor Selection wizard specifics to a separate table.
201 */
202 public List getPageDefinitions() throws DBException {
203 String id = getId();
204 if (id == null || id.length() == 0) {
205 throw new IllegalStateException("Must call 'setField(FLD_ID)' before calling "
206 + "getPageDefinitions()");
207 }
208 WizStep steps = new WizStep();
209
210 steps.setWizId(getId());
211
212 return (List) steps.searchAndRetrieveList(WizStep.FLD_ORDER);
213 }
214
215 /***
216 * One time intiialization of all the field types. Set all specifications
217 * here such as field names, table name, friendly name of the data object,
218 * characterset, etc.
219 *
220 * @throws DBException upon error
221 */
222 protected void setupFields() throws DBException {
223 if (getLogger().isDebugEnabled()) {
224 getLogger().debug("Initializing field members");
225 }
226
227 super.setupFields();
228 setTargetTable(TABLE_NAME);
229
230 setDescription("Wizard Definition");
231 setCharset("ISO-8859-1");
232
233 addField(FLD_ID, "auto-inc", 0, false, "Item ID");
234 addKey(FLD_ID);
235
236 addField(FLD_NAME, DBField.VARCHAR_TYPE, 254, false, "Name");
237 addField(FLD_WIZARD, DBField.VARCHAR_TYPE, 254, false, "Wizard");
238 addField(FLD_FACTORY, DBField.VARCHAR_TYPE, 254, false, "Factory");
239 addField(FLD_CONTROLLER, DBField.VARCHAR_TYPE, 254, true, "Wizard Controller");
240 addField(FLD_EDITOR_CONTROLLER, DBField.VARCHAR_TYPE, 254, true, "Wizard Editor Controller");
241 addField(FLD_ADDITIONAL_INFO, DBField.VARCHAR_TYPE, 254, true, "Additional Info Database Object Class");
242
243 addField(FLD_SUMMARY, DBField.TEXT_TYPE, 0, true, "Summary");
244
245
246 DBField fieldMeta = (DBField) getMetaData().getFieldMetadata(FLD_SUMMARY);
247 fieldMeta.setFilterClass(AllowedHtmlPlusURLFilter.class);
248
249 addDetail(WizStep.class.getName(), FLD_ID,
250 WizStep.FLD_WIZID);
251
252 setDefaultValue(FLD_CONTROLLER,
253 com.sri.emo.wizard.selection.WizardAction.class.getName());
254
255 setDefaultValue(FLD_WIZARD,
256 com.sri.emo.wizard.selection.EmoSelectionWizard
257 .class.getName());
258
259 setDefaultValue(FLD_FACTORY,
260 com.sri.emo.wizard.selection.EmoSelectionWizardFactory
261 .class.getName());
262
263 addDetail(WizStep.class.getName(),
264 FLD_ID, WizStep.FLD_WIZID);
265 }
266
267 /***
268 * Default class for additional information.
269 *
270 * @param newClass Class
271 * @throws DBException
272 */
273 public void setAdditionalInfo(Class newClass) throws DBException {
274 if (newClass == null) {
275 this.setField(FLD_ADDITIONAL_INFO, (String) null);
276 } else {
277 this.setField(FLD_ADDITIONAL_INFO, newClass.getName());
278 }
279 }
280
281 /***
282 * Retrieves the additional information class.
283 *
284 * @return Class or null if no additional information is set.
285 * @throws DBException
286 */
287 public Class getAdditionalInfoClass() throws DBException {
288 String classValue = this.getField(FLD_ADDITIONAL_INFO);
289 if (classValue == null || classValue.length() == 0) {
290 return null;
291 } else {
292 try {
293 return Thread.currentThread().getContextClassLoader().loadClass(classValue);
294 } catch (ClassNotFoundException ex) {
295 throw new DBException("Unable to locate class: " + classValue, ex);
296 }
297 }
298 }
299
300 /***
301 * Sets a new object to the additional info placeholder.
302 *
303 * @param replacementInfo DataObject
304 */
305 public void setAdditionalInfo(final JDBCDataObject replacementInfo) {
306 peerDataObject = replacementInfo;
307 }
308
309 /***
310 * Retrieves an additional information object associated with this class.
311 *
312 * @return DataObject or null if there is no info class associated with this
313 * wizard instance.
314 * @throws DBException upon general database error.
315 * @throws DBRecordNotFoundException if unable to locate the additional info.
316 */
317 public JDBCDataObject getAdditionalInfo() throws DBException, DBRecordNotFoundException {
318 if (peerDataObject != null) {
319 return peerDataObject;
320 }
321
322 Class infoClass = getAdditionalInfoClass();
323 if (infoClass == null) {
324 return null;
325 }
326
327 JDBCDataObject resultObject = (JDBCDataObject) DataObjectFactory.createDataObject(infoClass,
328 this.getDataContext(),
329 this.getRequestingUser());
330
331 if (!this.getStatus().equals(STATUS_NEW) && this.getId() != null) {
332 String idField = ((AdditionalInfo) resultObject).getIdField();
333 resultObject.set(idField, this.getId());
334
335 if (!resultObject.find()) {
336 throw new DBRecordNotFoundException("Unable to find additional info class of: " + infoClass.getName()
337 + " with key of: " + this.getId());
338 }
339
340 }
341
342
343
344 this.peerDataObject = resultObject;
345
346 return peerDataObject;
347 }
348
349
350 /***
351 * Override of standard checkfield to verify class name and factory name.
352 *
353 * @param fieldName the name of the field to check.
354 * @param fieldValue the value of the field to check.
355 * @throws DBException upon validation error.
356 */
357 public synchronized void checkField(final String fieldName,
358 final String fieldValue) throws com.jcorporate.expresso.core.db.DBException {
359 if (FLD_WIZARD.equals(fieldName)) {
360 validateClass(fieldName, fieldValue, com.sri.emo.wizard
361 .Wizard.class);
362 } else if (FLD_FACTORY.equals(fieldName)) {
363 validateClass(fieldName, fieldValue, com.sri.emo.wizard
364 .WizardFactory.class);
365 } else {
366 super.checkField(fieldName, fieldValue);
367 }
368 }
369
370 /***
371 * Validates a class by (1) name, and (2) makes sure it derives
372 * from the specified class.
373 *
374 * @param className the name of the class.
375 * @param requiredSuperclass the required superclass.
376 * @param fieldName the name of the field we're validating.
377 * @throws DBException upon validation error.
378 */
379 protected void validateClass(final String fieldName,
380 final String className,
381 final Class requiredSuperclass) throws DBException {
382 if (className == null || className.length() == 0) {
383 throw new DBException("Must have a value set for "
384 + getMetaData()
385 .getFieldMetadata(fieldName)
386 .getDescription());
387 }
388
389 try {
390 Class c = Class.forName(className,
391 false,
392 Thread.currentThread()
393 .getContextClassLoader());
394 if (!requiredSuperclass.isAssignableFrom(c)) {
395 throw new DBException("Class " + className +
396 " must be derived from: "
397 + requiredSuperclass.toString()
398 + "for field: "
399 + getMetaData()
400 .getFieldMetadata(fieldName)
401 .getDescription());
402 }
403 } catch (ClassNotFoundException ex) {
404 throw new DBException("Unable to find class: " + className);
405 }
406
407 }
408
409 /***
410 * Retrieve a list of pertinent decision steps for the current wizard.
411 *
412 * @return List a list of WizStep instances.
413 * @throws DBException upon error.
414 * <em>Only useful for Selection Wizards</em>
415 * @todo Refactor Selection wizard specifics to a separate table.
416 */
417 public List getPertinentDecisionSteps() throws
418 DBException {
419 List allSteps = getPageDefinitions();
420 if (allSteps.size() == 0) {
421
422 return new ArrayList();
423 }
424
425
426
427 ArrayList pertinentSteps = new ArrayList(allSteps.size() - 1);
428 for (int i = 0; i < allSteps.size(); i++) {
429 WizStep oneStep = (WizStep) allSteps.get(i);
430 int stepType = oneStep.getStepType();
431 switch (stepType) {
432 case PromptStepType.INSTANCE_PICKLIST:
433 case PromptStepType.CUSTOM_PICKLIST:
434 case PromptStepType.MODEL_PICKLIST:
435 ValidValue[] vv = oneStep.getMenuItems();
436 if (vv != null && vv.length > 0) {
437 pertinentSteps.add(oneStep);
438 }
439 break;
440
441 case PromptStepType.INSTRUCTIONS_ONLY:
442
443
444 continue;
445
446 case PromptStepType.TEXT_ENTRY:
447
448
449 continue;
450
451 default:
452 throw new IllegalStateException("InvalidInput Value: " + WizStep.FLD_STEP_TYPE + "=" + stepType);
453 }
454 }
455 return pertinentSteps;
456 }
457
458
459 /***
460 * Provide a transition for viewing this object, suitable for creating an
461 * HTTP link.
462 *
463 * @return transtion for viewing, including label for name of object; never null
464 * @throws DBException upon error.
465 */
466 public Transition getViewTrans() throws DBException {
467 Transition trans = new Transition(getWizName(), SelectionWizardManager.class,
468 SelectionWizardManager.STATE_PROMPT_EDIT);
469 trans.addParam(WizardController.WIZ_PARAMETER_ID, getId());
470 return trans;
471 }
472
473 /***
474 * Get the Wizard id.
475 *
476 * @return java.lang.String
477 * @throws DBException upon getField error
478 */
479 public String getId() throws DBException {
480 return getField(FLD_ID);
481 }
482
483 /***
484 * Get the Wizard name.
485 *
486 * @return java.lang.String
487 * @throws DBException upon getField error
488 */
489 public String getWizName() throws DBException {
490 return getField(FLD_NAME);
491 }
492
493 public void setId(String id) throws DBException {
494 setField(FLD_ID, id);
495 }
496
497 public String getWizardClass() throws DBException {
498 return getField(FLD_WIZARD);
499 }
500
501 public String getSummary() throws DBException {
502 return getField(FLD_SUMMARY);
503 }
504
505 public String getController() throws DBException {
506 return getField(FLD_CONTROLLER);
507 }
508
509 public void setId(int id) throws DBException {
510 setField(FLD_ID, id);
511 }
512
513 public String getSummaryRaw() throws DBException {
514 Filter old = setFilterClass(new RawFilter());
515 String raw = getSummary();
516 setFilterClass(old);
517
518 return raw;
519 }
520
521
522 /***
523 * Override of delete that deletes 'additional info' 1-1 mappings as well.
524 *
525 * @throws DBException
526 */
527 public void delete(final boolean deleteDetails) throws DBException {
528 DataObject additionalInfo = null;
529 String errorMessage = null;
530 try {
531 additionalInfo = this.getAdditionalInfo();
532 if (additionalInfo != null) {
533 additionalInfo.delete();
534
535 }
536 } catch (DBException ex) {
537 errorMessage = "Error deleting wizard definition additional info." + ((additionalInfo != null)
538 ? " additional info class: " + additionalInfo.getClass().getName() : "");
539 this.getLogger().error(errorMessage, ex);
540 throw new DBException(errorMessage, ex);
541 }
542
543 super.delete(deleteDetails);
544 }
545
546 /***
547 * Adds the record to the defined data source and adds the additional
548 * info dataobjects bound to this object as well.
549 *
550 * @throws DBException upon error.
551 */
552 public void add() throws DBException {
553
554 super.add();
555
556
557 JDBCDataObject additionalInfo = null;
558 String errorMessage = null;
559 try {
560 additionalInfo = this.getAdditionalInfo();
561 if (additionalInfo != null) {
562 if (!(additionalInfo instanceof AdditionalInfo)) {
563 throw new DBException("Class " + additionalInfo.getClass().getName() + " must implement interface "
564 + AdditionalInfo.class.getName());
565 }
566
567 additionalInfo.set(((AdditionalInfo) additionalInfo).getIdField(), this.get(FLD_ID));
568 additionalInfo.setConnection(this.getLocalConnection());
569
570 additionalInfo.add();
571 }
572 } catch (DBException ex) {
573 errorMessage = "Error adding wizard definition additional info." + ((additionalInfo != null)
574 ? " additional info class: " + additionalInfo.getClass().getName() : "");
575 this.getLogger().error(errorMessage, ex);
576 throw new DBException(errorMessage, ex);
577 }
578
579 }
580
581 /***
582 * Updates this object and any additional info objects bound to this
583 * wizard.
584 *
585 * @throws DBException upon error.
586 */
587 public void update() throws DBException {
588
589 super.update();
590
591
592 DataObject additionalInfo = null;
593 String errorMessage = null;
594 try {
595 additionalInfo = this.getAdditionalInfo();
596 if (additionalInfo != null) {
597 additionalInfo.update();
598 }
599 } catch (DBException ex) {
600 errorMessage = "Error updating wizard definition additional info." + ((additionalInfo != null)
601 ? " additional info class: " + additionalInfo.getClass().getName() : "");
602 this.getLogger().error(errorMessage, ex);
603 throw new DBException(errorMessage, ex);
604 }
605 }
606
607 /***
608 * Clears all field data as well as additional info.
609 *
610 * @throws DBException upon error.
611 */
612 public void clear() throws DBException {
613 this.peerDataObject = null;
614 super.clear();
615 }
616
617
618 public String toString() {
619 return "Wizard Definition Id: " + getKey();
620 }
621
622 }