View Javadoc

1   /* ===================================================================
2    * Copyright 2002-05 SRI International.
3    * Released under the MOZILLA PUBLIC LICENSE Version 1.1
4    * which can be obtained at http://www.mozilla.org/MPL/MPL-1.1.html
5    * This software is distributed on an "AS IS"
6    * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
7    * See the License for the specific language governing rights and
8    * limitations under the License.
9    * =================================================================== */
10  package com.sri.emo.wizard.creation.model;
11  
12  import java.io.*;
13  
14  import com.jcorporate.expresso.core.controller.*;
15  import com.jcorporate.expresso.core.db.*;
16  import com.sri.emo.dbobj.*;
17  import org.apache.commons.lang.builder.*;
18  import org.apache.log4j.*;
19  
20  
21  /***
22   * Metadata for each completion part.
23   *
24   * @author Michael Rimov
25   * @version 1.0
26   */
27  public class CreationPartsBean implements Serializable, Comparable {
28  
29      /***
30       * Field completion type. (wizard or fixed)
31       */
32      private FieldCompletion fieldCompletion;
33  
34      /***
35       * Is this a free text entry.
36       */
37      private boolean freeTextEntry;
38  
39      /***
40       * Minimum number of entries.
41       */
42      private Integer minEntries;
43  
44      /***
45       * Maximum number of entries.
46       */
47      private Integer maxEntries;
48  
49      /***
50       * The attached part.
51       */
52      private final Part attachedPart;
53  
54      /***
55       * The owning completion bean.
56       */
57      private final CreationBean owner;
58  
59      /***
60       * The step directive.
61       */
62      private String directive;
63  
64      /***
65       * The step helptext.
66       */
67      private String helpText;
68  
69      /***
70       * Is the step single value entry?
71       */
72      private boolean singleEntry;
73  
74      /***
75       * added by rich
76       * Allow for searching of existing nodes
77       */
78      private boolean search;
79      private String searchText;
80  
81      /***
82       * added by rich
83       * Allow for creation of a brand new node
84       */
85      private boolean create;
86      private String createText;
87  
88      /***
89       * added by rich
90       * Allow for browsing of existing nodes
91       */
92      private boolean browse;
93      private String browseText;
94  
95      /***
96       * added by rich
97       * Allow the user to skip this choice
98       */
99      private boolean required;
100 
101     /***
102      * Constructor that takes the parent bean and an associated <tt>Part</tt>
103      * object.
104      *
105      * @param myOwner CompletionBean the parent bean.
106      * @param myPart  Part the associated part.
107      * @throws DBException upon Part query error.
108      */
109     public CreationPartsBean(final CreationBean myOwner, final Part myPart) throws DBException {
110         attachedPart = myPart;
111         owner = myOwner;
112         freeTextEntry = !(myPart.hasPicklist() || myPart.isSharedNodeAttrib() || myPart.isHaveCustomHandler());
113         if (!myPart.isSingleValued()) {
114             minEntries = new Integer(1);
115             maxEntries = new Integer(1);
116             this.setSingleEntry(false);
117         } else {
118             minEntries = new Integer(1);
119             maxEntries = new Integer(1);
120             this.setSingleEntry(true);
121         }
122 
123         setDefaultDirective(myPart);
124         setDefaultCreateText(myPart);
125         setDefaultBrowseText(myPart);
126         setDefaultSearchText(myPart);
127     }
128 
129     /***
130      * Sets a default directive for the given part.  The text is varied
131      * depending on the metadata of the part.
132      *
133      * @param myPart Part the part to extract the computed directive for.
134      * @throws DBException upon error querying the Part.
135      */
136     private void setDefaultDirective(final Part myPart) throws DBException {
137         String partLabel = myPart.getPartLabel();
138 
139         if (myPart.hasPicklist()) {
140             if (myPart.isSingleValued()) {
141                 setDirective("Please select a value for <b>" + partLabel + "</b>");
142             } else {
143                 setDirective("Please choose values for <b>" + partLabel + "</b>");
144             }
145         } else {
146             if (myPart.isSingleValued()) {
147                 setDirective("Please enter a value for <b>" + partLabel+"</b>");
148             } else {
149                 setDirective("Please set values for <b>" + partLabel + "</b>");
150             }
151         }
152     }
153 
154     /***
155      * Sets a default create text for the given part.  The text is varied
156      * depending on the metadata of the part.
157      *
158      * @param myPart Part the part to extract the computed create text for.
159      * @throws DBException upon error querying the Part.
160      */
161     private void setDefaultCreateText(final Part myPart) throws DBException {
162         String partLabel = myPart.getPartLabel();
163         setCreateText("<b>Create</b> "+partLabel+":");
164     }
165     private void setDefaultBrowseText(final Part myPart) throws DBException {
166         String partLabel = myPart.getPartLabel();
167         setBrowseText("<b>Browse</b> for existing "+partLabel+":");
168     }
169     private void setDefaultSearchText(final Part myPart) throws DBException {
170         String partLabel = myPart.getPartLabel();
171         setSearchText("<b>Find</b> existing " + partLabel +
172                       ":<p>The Search Engine can search for keywords found in several attributes within " +
173                       partLabel + ".</p>");
174     }
175 
176     public CreationBean getOwner() {
177         return owner;
178     }
179 
180     public Part getPart() {
181         return attachedPart;
182     }
183 
184 
185     public void setFieldCompletion(FieldCompletion fieldCompletion) {
186         this.fieldCompletion = fieldCompletion;
187     }
188 
189     public void setDirective(String directive) {
190         this.directive = directive;
191     }
192 
193     public void setHelpText(String helpText) {
194         this.helpText = helpText;
195     }
196 
197     public void setSingleEntry(boolean singleEntry) {
198         this.singleEntry = singleEntry;
199     }
200 
201     public void setBrowse(boolean browse) {
202         this.browse = browse;
203     }
204 
205     public void setCreate(boolean create) {
206         this.create = create;
207     }
208 
209     public void setRequired(boolean required) {
210         this.required = required;
211     }
212 
213     public void setSearch(boolean search) {
214         this.search = search;
215     }
216 
217     public void setBrowseText(String browseText) {
218         this.browseText = browseText;
219     }
220 
221     public void setCreateText(String createText) {
222         this.createText = createText;
223     }
224 
225     public void setSearchText(String searchText) {
226         this.searchText = searchText;
227     }
228 
229     public void setMinEntries(int minEntries) {
230         this.minEntries = new Integer(minEntries);
231     }
232 
233     public void setMaxEntries(int maxEntries) {
234         this.maxEntries = new Integer(maxEntries);
235     }
236 
237 
238     public FieldCompletion getFieldCompletion() {
239         return fieldCompletion;
240     }
241 
242     public boolean isFreeTextEntry() {
243         return freeTextEntry;
244     }
245 
246     public Integer getMinEntries() {
247         return minEntries;
248     }
249 
250     public Integer getMaxEntries() {
251         return maxEntries;
252     }
253 
254     public String getDirective() {
255         return directive;
256     }
257 
258     public String getHelpText() {
259         return helpText;
260     }
261 
262     public boolean isSingleEntry() {
263         return singleEntry;
264     }
265 
266     public boolean isBrowse() {
267         return browse;
268     }
269 
270     public boolean isCreate() {
271         return create;
272     }
273 
274     public boolean isRequired() {
275         return required;
276     }
277 
278     public boolean isSearch() {
279         return search;
280     }
281 
282     public String getBrowseText() {
283         return browseText;
284     }
285 
286     public String getCreateText() {
287         return createText;
288     }
289 
290     public String getSearchText() {
291         return searchText;
292     }
293 
294     public boolean isFreeTextAllowed() throws DBException {
295         return !(this.getPart().hasPicklist() || getPart().isSharedNodeAttrib() || getPart().isHaveCustomHandler());
296     }
297 
298     public boolean isMinMaxAllowed() throws DBException {
299         return !this.getPart().isSingleValued();
300     }
301 
302     /***
303      * Compares this object with the specified object for order.  This implementation
304      * relies on the underlying parts for comparison.
305      *
306      * @param o the Object to be compared.
307      * @return a negative integer, zero, or a positive integer as this
308      *         object is less than, equal to, or greater than the specified object.
309      */
310     public int compareTo(Object o) {
311         assert o instanceof CreationPartsBean;
312 
313         int myOrderNumber = 0;
314         int otherOrderNumber = 0;
315         try {
316             CreationPartsBean other = (CreationPartsBean) o;
317 
318             //null checks
319             if (attachedPart == null && other.attachedPart != null) {
320                 return -1;
321             } else if (attachedPart != null && other.attachedPart == null) {
322                 return 1;
323             }
324 
325             //Same goes for the part number values
326             if ((attachedPart.getPartNum() == null
327                     || attachedPart.getPartNum().length() == 0) && !(other.attachedPart.getPartNum() == null
328                     || other.attachedPart.getPartNum().length() == 0)) {
329                 return -1;
330             } else if (!(attachedPart.getPartNum() == null
331                     || attachedPart.getPartNum().length() == 0) && (other.attachedPart.getPartNum() == null
332                     || other.attachedPart.getPartNum().length() == 0)) {
333                 return 1;
334             }
335 
336             //Ok, we passed null tests, continue.
337 
338             myOrderNumber = attachedPart.getPartNumInt();
339             otherOrderNumber = ((CreationPartsBean) o).attachedPart.getPartNumInt();
340 
341             if (myOrderNumber == otherOrderNumber) {
342                 return 0;
343             } else if (myOrderNumber > otherOrderNumber) {
344                 return 1;
345             } else {
346                 return -1;
347             }
348         } catch (DBException ex) {
349             throw new RuntimeException("error querying part order for comparison");
350         }
351     }
352 
353     /***
354      * Returns a string representation of the object.
355      *
356      * @return a string representation of the object.
357      */
358     public String toString() {
359         try {
360             return "Creation bean for Part ID: " + attachedPart.getPartNum();
361         } catch (DBException ex) {
362             return "Creation bean for Part ID (Cannot get id due to exception)";
363         }
364     }
365 
366     /***
367      * Validate the properties that have been set for this HTTP request,
368      * and return an <code>ActionErrors</code> object that encapsulates any
369      * validation errors that have been found.
370      *
371      * @param toPopulate The ErrorCollection we are using to populate with errors
372      *                   upon validation errors.
373      * @return ActionErrors
374      * @todo This is not a side-effect free function.  Redesign so that 'fixing'
375      * logic is centralized in the DBObject Converter.
376      */
377     public ErrorCollection validateAndAdjust(final ErrorCollection toPopulate) {
378 
379         //If it is a fixed value, then we don't give a hoot what
380         //they entered.
381         if (this.getFieldCompletion() == FieldCompletion.NOT_INCLUDED) {
382             return toPopulate;
383         }
384 
385         try {
386             if (this.getPart() == null) {
387                 toPopulate.addError("There is no attached part for this attribute: " + this.toString());
388             }
389 
390             if (this.isMinMaxAllowed()) {
391                 if (minEntries != null) {
392                     if (minEntries.intValue() < 0) {
393                         toPopulate.addError("Min Entries Value for '" + this.getPart().getPartLabel()
394                                 + "' must be greater than zero");
395                     }
396 
397                 }
398 
399                 if (maxEntries != null) {
400                     if (maxEntries.intValue() < 0) {
401                         toPopulate.addError("Max Entries Value for '" + this.getPart().getPartLabel()
402                                 + "' must be greater than zero");
403                     }
404                 }
405 
406                 if (maxEntries.intValue() < minEntries.intValue()) {
407                     toPopulate.addError("Max Entries for: " + this.getPart().getPartLabel()
408                             + " must be greater than Min Entries.");
409                 }
410             } else if (minEntries != null && minEntries.intValue() > 1) {
411                 toPopulate.addError(
412                         "Min Entries for: " + this.getPart().getPartLabel()
413                                 + " cannot be greater than '1'.  Automatically adjusting value.  Please verify and save the updated wizard.");
414                 minEntries = new Integer(1);
415             } else if (maxEntries != null && maxEntries.intValue() > 1) {
416                 toPopulate.addError(
417                         "Max Entries for: " + this.getPart().getPartLabel()
418                                 + " cannot be greater than '1'.  Automatically adjusting value.   Please verify and save the updated wizard.");
419                 maxEntries = new Integer(1);
420             }
421 
422             if (!this.isFreeTextAllowed() && this.isFreeTextEntry()) {
423                 toPopulate.addError(
424                         "Free Text Entry is set, but free text entry is not permitted by node type definition."
425                                 + " This has been corrected. Please Resubmit");
426                 this.freeTextEntry = false;
427             }
428 
429         } catch (DBException ex) {
430             Logger.getLogger(CreationPartsBean.class).error("Error validating part", ex);
431             throw new RuntimeException(
432                     "Error grabbing part label for: " + getPart().toString() + ". (Additional information logged)");
433         }
434 
435         return toPopulate;
436     }
437 
438     /***
439      * Indicates whether some other object is "equal to" this one.
440      *
441      * @param obj the reference object with which to compare.
442      * @return <code>true</code> if this object is the same as the obj
443      *         argument; <code>false</code> otherwise.
444      */
445     public boolean equals(Object obj) {
446         if (!(obj instanceof CreationPartsBean)) {
447             return false;
448         }
449 
450         CreationPartsBean other = (CreationPartsBean) obj;
451 
452         EqualsBuilder equalsBuilder = new EqualsBuilder()
453                 .append(attachedPart, other.attachedPart)
454                 .append(directive, other.directive)
455                 .append(fieldCompletion, other.fieldCompletion)
456                 .append(freeTextEntry, other.freeTextEntry)
457                 .append(helpText, other.helpText)
458                 .append(maxEntries, other.maxEntries)
459                 .append(minEntries, other.minEntries)
460                 .append(singleEntry, other.singleEntry);
461 
462         return equalsBuilder.isEquals();
463     }
464 
465     /***
466      * Returns a hash code value for the object.
467      *
468      * @return a hash code value for this object.
469      */
470     public int hashCode() {
471         try {
472             HashCodeBuilder hashCodeBuilder = new HashCodeBuilder(481, 31)
473                     .append(attachedPart.getId())
474                     .append(directive)
475                     .append(fieldCompletion)
476                     .append(freeTextEntry)
477                     .append(helpText)
478                     .append(maxEntries)
479                     .append(minEntries)
480                     .append(singleEntry);
481 
482             return hashCodeBuilder.toHashCode();
483         } catch (DBException ex) {
484             return 0;
485         }
486     }
487 
488 
489 }