View Javadoc

1   package com.sri.emo.wizard.creation;
2   
3   import java.io.*;
4   import java.util.*;
5   
6   import com.jcorporate.expresso.core.controller.*;
7   import com.jcorporate.expresso.core.dataobjects.*;
8   import com.jcorporate.expresso.core.db.*;
9   import com.jcorporate.expresso.core.db.exception.*;
10  import com.jcorporate.expresso.core.registry.*;
11  import com.sri.common.util.*;
12  import com.sri.emo.dbobj.*;
13  import com.sri.emo.wizard.*;
14  import com.sri.emo.wizard.defaults.*;
15  import com.sri.emo.wizard.creation.model.*;
16  
17  /***
18   * A creation wizard, as originally copied from Completion wizard with
19   * some modifications done to allow for the initialization page to be inserted
20   * For the completion wizard pages, ids are java.lang.Integer types with values
21   * <= 0 are special pages.  Any values >0 represent a corresponding Part.
22   * Developers should use isPartsPage() for interpretation of this, however.
23   *
24   * @author Michael Rimov
25   *
26   */
27  public class EmoCreationWizardOld extends SequentialWizard {
28  
29      /***
30       * Constant for the title page id.
31       */
32      public static final String TITLE_PAGE_ID = "-2";
33  
34      /***
35       * Constant for the initialization page id
36       */
37      public static final String INITIALIZATION_PAGE_ID = "-3";
38  
39      /***
40       * Constant for the last page (where 'finish' appears) id.
41       */
42      public static final String FINAL_PAGE_ID = "-1";
43  
44  
45      /***
46       * Underlying completion data bean. This object is not serialized due
47       * to space considerations since it is stateless for the given wizard.
48       * However, for saving state and reconsistuting it via the <tt>Memento</tt>
49       * pattern, then it is set/reset during that phase.
50       */
51      private transient CreationBean completionBean;
52  
53  
54      /***
55       * Constructs an emo completion wizard.
56       *
57       * @param wizMonitor WizardMonitor
58       * @param steps      WizardPage[]
59       */
60      public EmoCreationWizardOld(final WizardMonitor wizMonitor, final WizardPage[] steps) {
61          super(wizMonitor, steps);
62      }
63  
64  
65      /***
66       * Override of Sequential's onNextPage to allow for validation of values
67       * as they're entered.
68       *
69       * @param previousPage     WizardPage
70       * @param nextPage         The next page that will be invoked.  A 'lookahead' so
71       *                         to speak.
72       * @param previousPageData Serializable
73       * @return boolean true if the wizard can proceed, false if the previous
74       *         page needs to be displayed with validation errors.
75       * @throws WizardException upon error.
76       * @throws AssertionError  if the previouspage id is the final page.
77       */
78      protected boolean onNextPage(final WizardPage previousPage, final WizardPage nextPage,
79                                   final Serializable previousPageData) throws WizardException, AssertionError {
80  
81          Integer previousPageId = (Integer) previousPage.getId();
82          assert previousPageId != null;
83          if(isInitializationPage(previousPageId)){
84              return validateInitializationPageData(previousPage, previousPageData);
85          }
86          //If we have a part page
87          else if (isPartsPage(previousPageId)) {
88              //validate part entry.
89              return validatePartPageData(previousPage, previousPageData);
90              //Or if we have a title page.
91          } else if (TITLE_PAGE_ID.equals(previousPageId.toString())) {
92              //Then return true/
93              return true;
94  
95              //Or if we have the final page.
96          } else if (FINAL_PAGE_ID.equals(previousPageId.toString())) {
97              assert false:"Final page should not have gotten 'onNext' event";
98              throw new WizardException("Internal Error: received 'next' where the previous page "
99                      + "was the final page.  Wizard is incorrectly constructed.");
100         } else {
101 
102             //Consider if the next page is a multi attribute page, then the current
103             //date must be the number of steps.
104             if (nextPage.getMetadata() instanceof MultiEntryMetadata) {
105                 boolean returnValue = validatePreMultiAttributesPage(previousPage, nextPage, previousPageData);
106                 returnValue &= super.onNextPage(previousPage, nextPage, previousPageData);
107                 return returnValue;
108 //                if (returnValue && ((MultiEntryWizardPage)nextPage).getNumEntries() == 0) {
109 //                    return returnValue
110 //                }
111             }
112 
113             //
114             //We don't have to do anything to make everything work.
115             //
116         }
117 
118         //
119         //Super class will return false if the page itself has errors.
120         //
121         return super.onNextPage(previousPage, nextPage, previousPageData);
122     }
123 
124     /***
125      * validateInitializationPageData
126      *
127      * @param previousPage WizardPage
128      * @param previousPageData Serializable
129      * @return boolean
130      */
131     private boolean validateInitializationPageData(WizardPage src,
132             Serializable previousPageData) {
133         List list = (List)previousPageData;
134         String title  = (String) list.get(0);
135         if(title == null || title.length() == 0){
136             src.addError("Please enter a title.");
137             return false;
138         }
139             try {
140                 Node testNode = new Node(RequestRegistry.getUser());
141                 testNode.setNodeTitle(title);
142                 System.out.println("node type = " + testNode.getNodeType());
143                 if (testNode.find()) {
144                     src.addError(
145                             "Title is already in use; please choose another.");
146                     return false;
147                 }
148             } catch (DBException ex1) {
149                 src.addError(ex1.getMessage());
150                 return false;
151             }
152         try {
153             completionBean.getCurrentNode().set(Node.NODE_TITLE, title);
154         } catch (DataException ex) {
155             src.addError(ex.getMessage());
156             return false;
157         }
158         return true;
159     }
160 
161     /***
162      * isInitializationPage
163      *
164      * @param previousPageId Integer
165      * @return boolean
166      */
167     private boolean isInitializationPage(Integer previousPageId) {
168 
169         Integer i = new Integer(INITIALIZATION_PAGE_ID);
170         return i.equals(previousPageId);
171     }
172 
173 
174     private boolean validatePreMultiAttributesPage(final WizardPage previousPage, final WizardPage nextPage,
175                                                    final Serializable previousPageData) {
176 //        if (previousPageData == null) {
177 //            previousPage.addError("You must enter a value for this page");
178 //            return false;
179 //        }
180 
181         MultiEntryWizardPage multiNextPage = (MultiEntryWizardPage) nextPage;
182         MultiEntryMetadata nextPageMetadata = (MultiEntryMetadata) nextPage.getMetadata();
183 
184         int numEntries = 0;
185         try {
186 
187             if (previousPageData == null || ((String) previousPageData).trim().length() == 0) {
188                 numEntries = 0;
189             } else {
190                 numEntries = Integer.parseInt((String) previousPageData);
191             }
192         } catch (NumberFormatException ex) {
193             previousPage.addError("You must enter a valid number for this page");
194             return false;
195         }
196 
197         boolean hadError = false;
198 //        if (nextPageMetadata.getMinEntries() != null
199 //                && numEntries < nextPageMetadata.getMinEntries().intValue()) {
200 //            previousPage.addError(
201 //                "Too few. You must enter a value greater than or equal to the minimum number of entries: "
202 //                + nextPageMetadata.getMinEntries());
203 //            hadError = true;
204 //        }
205 
206         if (nextPageMetadata.getMaxEntries() != null
207                 && numEntries > nextPageMetadata.getMaxEntries().intValue()) {
208             previousPage.addError(
209                     "Too many. You must enter a value less than or equal to the maximum number of entries: "
210                             + nextPageMetadata.getMaxEntries());
211             hadError = true;
212         }
213 
214         if (hadError) {
215             return false;
216         }
217 
218         multiNextPage.setNumEntries(numEntries);
219         return true;
220     }
221 
222     /***
223      * Constant for the minimum possible part number.  Anything else is a
224      * 'special page' of some sort.
225      */
226     private static final int MIN_PARTS_NUMBER = 0;
227 
228     /***
229      * Overridden target node id.  This must be explicitly set by the
230      * wizard controller. Otherwise we use the completion bean.
231      */
232 //    private String targetNodeId;
233 
234     /***
235      * Checks if the given page Id indicates it is a
236      * 'Parts' page.
237      *
238      * @param pageId Integer
239      * @return boolean
240      */
241     protected boolean isPartsPage(final Integer pageId) {
242         assert pageId != null;
243 
244         return pageId.intValue() >= MIN_PARTS_NUMBER;
245     }
246 
247     /***
248      * @param src         WizardPage
249      * @param enteredData Serializable
250      * @return boolean true if the data was validated.
251      * @throws WizardException upon error.
252      */
253     private boolean validatePartPageData(final WizardPage src, final Serializable enteredData) throws WizardException {
254         int partId = ((Integer) src.getId()).intValue();
255 
256         try {
257             Part onePart = new Part();
258             onePart.setPartId(partId);
259             onePart.retrieve();
260             //If single valued, then validate it.
261 //            * @todo Finish here when Part has custom handler.
262             if (onePart.isSingleValued()) {
263                 if (enteredData == null) {
264                     src.addError("Please enter a value for this page.");
265                     return false;
266                 }
267             }
268         } catch (DBRecordNotFoundException ex) {
269             throw new WizardException("Could not find part of id: " + partId
270                     + " perhaps it was deleted by someone else?", ex);
271         } catch (Throwable ex) {
272             throw new WizardException("Error processing page for part id: " + partId, ex);
273         }
274 
275         return true;
276     }
277 
278 
279     /***
280      * This version returns a <tt>Node<tt> instance if one has
281      * been successfully created.
282      * <p>{@inheritDoc}</p>
283      *
284      * @param src             WizardPage the source of the event.
285      * @param data            This class expects a string for the data.
286      * @param additonalParams anything that the underlying wizard needs. The
287      *                        values are set by the Application Controller.
288      * @return An instance of a {@link com.sri.emo.dbobj.Node} object
289      *         that represents the node the Decision Matrix returned or null if
290      *         there was no equivilant data found.
291      * @throws WizardException upon error.
292      */
293     public Object processFinish(final WizardPage src, final Serializable data,
294                                 final Map additonalParams) throws WizardException {
295         super.processFinish(src, data, additonalParams);
296 
297         assert src != null;
298 
299         Node node = getCompletionBean().getCurrentNode();
300         System.out.println("processFinish : " + node.toDebugString());
301         try {
302             if(!verifyRequiredAttributes(src)){
303                 return null;
304             }
305             copyReqDataIntoTargetNode(node);
306             node.add();
307             copyDataIntoTargetNode(node);
308         } catch (DBException ex) {
309             src.addError(ex.getMessage());
310             throw new WizardException(ex);
311         } catch (Exception e) {
312             src.addError(e.getMessage());
313 
314             if (e instanceof RuntimeException) {
315                 throw (RuntimeException) e;
316             } else {
317                 throw new WizardException(e);
318             }
319         }
320         // only save data if we have 'dynamic target', i.e., specified by param at beginning of
321         // web call, as opposed to 'model' target ID, which was used to design this wizard
322 //        if (this.isDynamicTarget()) {
323 //            try {
324 //                node = new Node();
325 //                node.setNodeId(getTargetNodeId());
326 //                node.retrieve();
327 //
328 //                copyDataIntoTargetNode(node);
329 //
330 //            } catch (DBRecordNotFoundException ex) {
331 //                String message = "Could not find node of id: " + getTargetNodeId();
332 //                src.addError(message + " with error: " + ex.getMessage());
333 //                throw new WizardException(message, ex);
334 //            } catch (Exception e) {
335 //                src.addError(e.getMessage());
336 //
337 //                if (e instanceof RuntimeException) {
338 //                    throw (RuntimeException) e;
339 //                } else {
340 //                    throw new WizardException(e);
341 //                }
342 //            }
343 //        } else {
344 //            src.addError("Cannot save to source of wizard design; expected a different (cloned?) destination");
345 //        }
346 
347         return node;
348     }
349 
350     /***
351      * verifyRequiredAttributes
352      */
353     private boolean verifyRequiredAttributes(WizardPage src) throws DBException,
354             NumberFormatException, WizardException {
355         CreationBean completionBean = this.getCompletionBean();
356 
357         boolean requiredFilled = true;
358 
359         for (Iterator partsIterator = completionBean.getCompletionParts().iterator(); partsIterator.hasNext();) {
360             CreationPartsBean onePartBean = (CreationPartsBean) partsIterator.next();
361             //Skip parts beans that have no data.
362             if (onePartBean.getFieldCompletion() == FieldCompletion.NOT_INCLUDED) {
363                 continue;
364             }
365 
366             Part currentPart = onePartBean.getPart();
367 //            System.out.println("working on part type " + currentPart.getPartType());
368 
369             //Retrieves the data value for that part.
370             Object wizardData = this.getAllData().get(new Integer(currentPart.getId()));
371             if(onePartBean.isRequired()){
372                 System.out.println(currentPart.getPartType() + " is required");
373                 System.out.println("data = '" + wizardData + "' class:"+wizardData.getClass());
374                 if(wizardData == null){
375                     src.addError(currentPart.getPartLabel() + " was marked as a required field, but has not been set, please fix.");
376                     requiredFilled = false;
377                 }
378                 else if(wizardData instanceof Collection &&
379                    ((Collection)wizardData).size() == 0){
380                     src.addError(currentPart.getPartLabel() + " was marked as a required field, but has not been set, please fix.");
381                     requiredFilled = false;
382                 }
383             }
384         }
385         return requiredFilled;
386     }
387 
388     /***
389      * copyReqDataIntoTargetNode
390      *
391      * @param node Node
392      */
393     private void copyReqDataIntoTargetNode(Node node) throws DataException {
394         Map allData = this.getAllData();
395         System.out.println("All Data = " +
396                            StringUtil.toString(allData.keySet().iterator()));
397 //        System.out.println("init page class = " + allData.get(new Integer(EmoTemplateWizard.
398 //                INITIALIZATION_PAGE_ID)).getClass());
399         List list = (List)allData.get(new Integer(EmoCreationWizardOld.
400                 INITIALIZATION_PAGE_ID));
401         String title  = (String) list.get(0);
402         String summary = (String) list.get(1);
403         String comment = (String) list.get(2);
404         System.out.println("found title as '" + title + "'");
405         node.set(Node.NODE_TITLE, title);
406         node.set(Node.NODE_ANNOTATION, summary);
407         node.set(Node.NODE_COMMENT, comment);
408     }
409 
410 
411     /***
412      * Returns true if the dynamic target has been specified.
413      *
414      * @return boolean
415      */
416     protected boolean isDynamicTarget() {
417         //changed by rich
418         //always dynamic target?
419         return true;
420 //        if (this.getCompletionBean().getTargetId().intValue() == Integer.parseInt(this.getTargetNodeId())) {
421 //            return false;
422 //        } else {
423 //            return true;
424 //        }
425     }
426 
427     /***
428      * Copies the wizard data into the given node.
429      *
430      * @param target Node The node that is set to receive all the data.
431      * @throws Exception upon consturction error, and database errors.
432      */
433     private void copyDataIntoTargetNode(final Node target) throws Exception {
434         CreationBean completionBean = this.getCompletionBean();
435 
436 
437 
438         for (Iterator partsIterator = completionBean.getCompletionParts().iterator(); partsIterator.hasNext();) {
439             CreationPartsBean onePartBean = (CreationPartsBean) partsIterator.next();
440             //Skip parts beans that have no data.
441             if (onePartBean.getFieldCompletion() == FieldCompletion.NOT_INCLUDED) {
442                 continue;
443             }
444 
445             Part currentPart = onePartBean.getPart();
446             System.out.println("working on part type " + currentPart.getPartType());
447 
448             //Retrieves the data value for that part.
449             Object wizardData = this.getAllData().get(new Integer(currentPart.getId()));
450 
451             if (currentPart.isHaveCustomHandler()) {
452 
453                 CustomPartHandlerMetadata meta = (CustomPartHandlerMetadata) getCurrentPage().getMetadata();
454                 IPartHandler handler = meta.getCustomHandler();
455                 List inputs = meta.getInputList();
456 
457                 for (Iterator iterator = inputs.iterator(); iterator.hasNext();) {
458                     Input input = (Input) iterator.next();
459                     handler.saveInput(input);
460                 }
461 
462             } else if (currentPart.isOwnedAttribute()) {
463                 //TODO Transaction Me
464                 if (currentPart.isMultipleAllowed()) {
465                     List valueList = (List) wizardData;
466 //                    assert valueList != null:"Got null values from wizard page: " + onePartBean.toString();
467                     if (valueList == null) {
468                         valueList = new ArrayList(0);
469                     }
470 
471                     Attribute[] attributes = target.getAttributes(currentPart.getPartType());
472                     //Don't worry about existing attributes since the wizard ones replace
473                     //whatever is there, so we go from there.
474                     for (int attributeIndex = 0; attributeIndex < attributes.length; attributeIndex++) {
475                         attributes[attributeIndex].delete(true);
476                     }
477 
478                     for (Iterator pageValuesIterator = valueList.iterator(); pageValuesIterator.hasNext();) {
479                         String onePageValue = (String) pageValuesIterator.next();
480                         System.out.println("adding attribute " + currentPart.getPartType() + " as " + onePageValue);
481                         target.addAttribute(currentPart.getPartType(), onePageValue, "");
482                     }
483 
484                 } else {
485 //                    System.out.println("
486                     Attribute[] attributes = target.getAttributes(currentPart.getPartType());
487                     System.out.println("attribute.length = " + attributes.length);
488                     for (int i = 0; i < attributes.length; i++) {
489                         System.out.println(attributes[i].getAttribValue());
490                     }
491 //                    System.out.println(StringUtil.toString(attributes));
492                     assert attributes.length == 0 || attributes.length == 1:
493                             "Expected only zero or one attributes returned for single attribute";
494 
495                     if (attributes.length == 0) {
496                         if (wizardData != null) {
497                             target.addAttribute(currentPart.getPartType(), wizardData.toString(), "");
498                         }
499                     } else {
500                         if (wizardData == null) {
501                             target.removeAttribute(attributes[0].getAttribId());
502                         } else {
503                             target.updateAttribute(attributes[0].getAttribId(), wizardData.toString(), "");
504                         }
505                     }
506                 }
507 
508             } else if (currentPart.isSharedNodeAttrib()) {
509                 //TODO Transaction Me
510                 assert wizardData instanceof Set;
511 
512                 Set allRelationsParameterMap = (Set) wizardData;
513                 if (allRelationsParameterMap == null) {
514                     allRelationsParameterMap = new HashSet(0);
515                 }
516                 String[] allRelationIds = (String[]) allRelationsParameterMap.toArray(
517                         new String[allRelationsParameterMap.size()]);
518 
519                 target.updateNodeRelations(currentPart.getPartType(), currentPart.getNodeRelation(), allRelationIds);
520             }
521 
522         }
523     }
524 
525 // commented out by rich, we use the node within the templatebean instead
526 //of a target node within the DB
527 //    public String getTargetNodeId() {
528 //        assert completionBean != null;
529 //
530 //        if (targetNodeId == null) {
531 //            return this.completionBean.getTargetId().toString();
532 //        } else {
533 //            return targetNodeId;
534 //        }
535 //    }
536 
537 //    public Node getTargetNode() throws WizardException {
538 //        try {
539 //            Node n = new Node();
540 //            n.setNodeId(this.getTargetNodeId());
541 //            n.retrieve();
542 //            return n;
543 //        } catch (DBRecordNotFoundException ex) {
544 //            throw new WizardException("Could no longer find template of id: " + getTargetNodeId()
545 //                    + " perhaps someone else deleted it?");
546 //        } catch (DBException ex) {
547 //            throw new WizardException("Error querying database", ex);
548 //        }
549 //    }
550 
551     /***
552      * Sets the underlying completion bean.
553      *
554      * @param completionBean CompletionBean
555      */
556     public void setCompletionBean(final CreationBean completionBean) {
557         this.completionBean = completionBean;
558     }
559 
560 //    public void setTargetNodeId(final String targetNodeId) {
561 //        this.targetNodeId = targetNodeId;
562 //    }
563 
564     public CreationBean getCompletionBean() {
565         return completionBean;
566     }
567 
568 
569 }