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.completion.model;
11  
12  import com.jcorporate.expresso.core.controller.ErrorCollection;
13  import com.jcorporate.expresso.core.db.DBException;
14  import com.sri.emo.dbobj.Part;
15  import org.apache.commons.lang.builder.EqualsBuilder;
16  import org.apache.commons.lang.builder.HashCodeBuilder;
17  import org.apache.log4j.Logger;
18  
19  import java.io.Serializable;
20  
21  
22  /***
23   * Metadata for each completion part.
24   *
25   * @author Michael Rimov
26   * @version 1.0
27   */
28  public class CompletionPartsBean implements Serializable, Comparable {
29  
30      /***
31  	 * 
32  	 */
33  	private static final long serialVersionUID = 1L;
34  
35  	/***
36       * Field completion type. (wizard or fixed)
37       */
38      private FieldCompletion fieldCompletion;
39  
40      /***
41       * Is this a free text entry.
42       */
43      private boolean freeTextEntry;
44  
45      /***
46       * Minimum number of entries.
47       */
48      private Integer minEntries;
49  
50      /***
51       * Maximum number of entries.
52       */
53      private Integer maxEntries;
54  
55      /***
56       * The attached part.
57       */
58      private final Part attachedPart;
59  
60      /***
61       * The owning completion bean.
62       */
63      private final CompletionBean owner;
64  
65      /***
66       * The step directive.
67       */
68      private String directive;
69  
70      /***
71       * The step helptext.
72       */
73      private String helpText;
74  
75      /***
76       * Is the step single value entry?
77       */
78      private boolean singleEntry;
79  
80      /***
81       * Constructor that takes the parent bean and an associated <tt>Part</tt>
82       * object.
83       *
84       * @param myOwner CompletionBean the parent bean.
85       * @param myPart  Part the associated part.
86       * @throws DBException upon Part query error.
87       */
88      public CompletionPartsBean(final CompletionBean myOwner, final Part myPart) throws DBException {
89          attachedPart = myPart;
90          owner = myOwner;
91          freeTextEntry = !(myPart.hasPicklist() || myPart.isSharedNodeAttrib() || myPart.isHaveCustomHandler());
92          if (!myPart.isSingleValued()) {
93              minEntries = new Integer(1);
94              maxEntries = new Integer(1);
95              this.setSingleEntry(false);
96          } else {
97              minEntries = new Integer(1);
98              maxEntries = new Integer(1);
99              this.setSingleEntry(true);
100         }
101 
102         setDefaultDirective(myPart);
103     }
104 
105     /***
106      * Sets a default directive for the given part.  The text is varied
107      * depending on the metadata of the part.
108      *
109      * @param myPart Part the part to extract the computed directive for.
110      * @throws DBException upon error querying the Part.
111      */
112     private void setDefaultDirective(final Part myPart) throws DBException {
113         String partLabel = myPart.getPartLabel();
114 
115         if (myPart.hasPicklist()) {
116             if (myPart.isSingleValued()) {
117                 setDirective("Please select a value for " + partLabel);
118             } else {
119                 setDirective("Please choose values for " + partLabel);
120             }
121         } else {
122             if (myPart.isSingleValued()) {
123                 setDirective("Please enter a value for " + partLabel);
124             } else {
125                 setDirective("Please set values for " + partLabel);
126             }
127         }
128     }
129 
130 
131     public CompletionBean getOwner() {
132         return owner;
133     }
134 
135     public Part getPart() {
136         return attachedPart;
137     }
138 
139 
140     public void setFieldCompletion(FieldCompletion fieldCompletion) {
141         this.fieldCompletion = fieldCompletion;
142     }
143 
144     public void setDirective(String directive) {
145         this.directive = directive;
146     }
147 
148     public void setHelpText(String helpText) {
149         this.helpText = helpText;
150     }
151 
152     public void setSingleEntry(boolean singleEntry) {
153         this.singleEntry = singleEntry;
154     }
155 
156     public void setMinEntries(int minEntries) {
157         this.minEntries = new Integer(minEntries);
158     }
159 
160     public void setMaxEntries(int maxEntries) {
161         this.maxEntries = new Integer(maxEntries);
162     }
163 
164 
165     public FieldCompletion getFieldCompletion() {
166         return fieldCompletion;
167     }
168 
169     public boolean isFreeTextEntry() {
170         return freeTextEntry;
171     }
172 
173     public Integer getMinEntries() {
174         return minEntries;
175     }
176 
177     public Integer getMaxEntries() {
178         return maxEntries;
179     }
180 
181     public String getDirective() {
182         return directive;
183     }
184 
185     public String getHelpText() {
186         return helpText;
187     }
188 
189     public boolean isSingleEntry() {
190         return singleEntry;
191     }
192 
193     public boolean isFreeTextAllowed() throws DBException {
194         return !(this.getPart().hasPicklist() || getPart().isSharedNodeAttrib() || getPart().isHaveCustomHandler());
195     }
196 
197     public boolean isMinMaxAllowed() throws DBException {
198         return !this.getPart().isSingleValued();
199     }
200 
201     /***
202      * Compares this object with the specified object for order.  This implementation
203      * relies on the underlying parts for comparison.
204      *
205      * @param o the Object to be compared.
206      * @return a negative integer, zero, or a positive integer as this
207      *         object is less than, equal to, or greater than the specified object.
208      */
209     public int compareTo(Object o) {
210         assert o instanceof CompletionPartsBean;
211 
212         int myOrderNumber = 0;
213         int otherOrderNumber = 0;
214         try {
215             CompletionPartsBean other = (CompletionPartsBean) o;
216 
217             //null checks
218             if (attachedPart == null && other.attachedPart != null) {
219                 return -1;
220             } else if (attachedPart != null && other.attachedPart == null) {
221                 return 1;
222             }
223 
224             //Same goes for the part number values
225             if ((attachedPart.getPartNum() == null
226                     || attachedPart.getPartNum().length() == 0) && !(other.attachedPart.getPartNum() == null
227                     || other.attachedPart.getPartNum().length() == 0)) {
228                 return -1;
229             } else if (!(attachedPart.getPartNum() == null
230                     || attachedPart.getPartNum().length() == 0) && (other.attachedPart.getPartNum() == null
231                     || other.attachedPart.getPartNum().length() == 0)) {
232                 return 1;
233             }
234 
235             //Ok, we passed null tests, continue.
236 
237             myOrderNumber = attachedPart.getPartNumInt();
238             otherOrderNumber = ((CompletionPartsBean) o).attachedPart.getPartNumInt();
239 
240             if (myOrderNumber == otherOrderNumber) {
241                 return 0;
242             } else if (myOrderNumber > otherOrderNumber) {
243                 return 1;
244             } else {
245                 return -1;
246             }
247         } catch (DBException ex) {
248             throw new RuntimeException("error querying part order for comparison");
249         }
250     }
251 
252     /***
253      * Returns a string representation of the object.
254      *
255      * @return a string representation of the object.
256      */
257     public String toString() {
258         try {
259             return "Completion bean for Part ID: " + attachedPart.getPartNum();
260         } catch (DBException ex) {
261             return "Completion bean for Part ID (Cannot get id due to exception)";
262         }
263     }
264 
265     /***
266      * Validate the properties that have been set for this HTTP request,
267      * and return an <code>ActionErrors</code> object that encapsulates any
268      * validation errors that have been found.
269      *
270      * @param toPopulate The ErrorCollection we are using to populate with errors
271      *                   upon validation errors.
272      * @return ActionErrors
273      * @todo This is not a side-effect free function.  Redesign so that 'fixing'
274      * logic is centralized in the DBObject Converter.
275      */
276     public ErrorCollection validateAndAdjust(final ErrorCollection toPopulate) {
277 
278         //If it is a fixed value, then we don't give a hoot what
279         //they entered.
280         if (this.getFieldCompletion() == FieldCompletion.FIXED) {
281             return toPopulate;
282         }
283 
284         try {
285             if (this.getPart() == null) {
286                 toPopulate.addError("There is no attached part for this attribute: " + this.toString());
287             }
288 
289             if (this.isMinMaxAllowed()) {
290                 if (minEntries != null && minEntries.intValue() < 0) {
291                     toPopulate.addError("Min Entries Value for '" + this.getPart().getPartLabel()
292                             + "' must be greater than zero");
293                 }
294 
295                 if (maxEntries != null && maxEntries.intValue() < 0) {
296                     toPopulate.addError("Max Entries Value for '" + this.getPart().getPartLabel()
297                             + "' must be greater than zero");
298                 }
299 
300                 if (maxEntries.intValue() < minEntries.intValue()) {
301                     toPopulate.addError("Max Entries for: " + this.getPart().getPartLabel()
302                             + " must be greater than Min Entries.");
303                 }
304             } else if (minEntries != null && minEntries.intValue() > 1) {
305                 toPopulate.addError(
306                         "Min Entries for: " + this.getPart().getPartLabel()
307                                 + " cannot be greater than '1'.  Automatically adjusting value.  Please verify and save the updated wizard.");
308                 minEntries = new Integer(1);
309             } else if (maxEntries != null && maxEntries.intValue() > 1) {
310                 toPopulate.addError(
311                         "Max Entries for: " + this.getPart().getPartLabel()
312                                 + " cannot be greater than '1'.  Automatically adjusting value.   Please verify and save the updated wizard.");
313                 maxEntries = new Integer(1);
314             }
315 
316             if (!this.isFreeTextAllowed() && this.isFreeTextEntry()) {
317                 toPopulate.addError(
318                         "Free Text Entry is set, but free text entry is not permitted by node type definition."
319                                 + " This has been corrected. Please Resubmit");
320                 this.freeTextEntry = false;
321             }
322 
323         } catch (DBException ex) {
324             Logger.getLogger(CompletionPartsBean.class).error("Error validating part", ex);
325             throw new RuntimeException(
326                     "Error grabbing part label for: " + getPart().toString() + ". (Additional information logged)");
327         }
328 
329         return toPopulate;
330     }
331 
332     /***
333      * Indicates whether some other object is "equal to" this one.
334      *
335      * @param obj the reference object with which to compare.
336      * @return <code>true</code> if this object is the same as the obj
337      *         argument; <code>false</code> otherwise.
338      */
339     public boolean equals(Object obj) {
340         if (!(obj instanceof CompletionPartsBean)) {
341             return false;
342         }
343 
344         CompletionPartsBean other = (CompletionPartsBean) obj;
345 
346         EqualsBuilder equalsBuilder = new EqualsBuilder()
347                 .append(attachedPart, other.attachedPart)
348                 .append(directive, other.directive)
349                 .append(fieldCompletion, other.fieldCompletion)
350                 .append(freeTextEntry, other.freeTextEntry)
351                 .append(helpText, other.helpText)
352                 .append(maxEntries, other.maxEntries)
353                 .append(minEntries, other.minEntries)
354                 .append(singleEntry, other.singleEntry);
355 
356         return equalsBuilder.isEquals();
357     }
358 
359     /***
360      * Returns a hash code value for the object.
361      *
362      * @return a hash code value for this object.
363      */
364     public int hashCode() {
365         try {
366             HashCodeBuilder hashCodeBuilder = new HashCodeBuilder(481, 31)
367                     .append(attachedPart.getId())
368                     .append(directive)
369                     .append(fieldCompletion)
370                     .append(freeTextEntry)
371                     .append(helpText)
372                     .append(maxEntries)
373                     .append(minEntries)
374                     .append(singleEntry);
375 
376             return hashCodeBuilder.toHashCode();
377         } catch (DBException ex) {
378             return 0;
379         }
380     }
381 
382 
383 }