View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.core.api.uif;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.List;
22  
23  import javax.xml.bind.annotation.XmlAccessType;
24  import javax.xml.bind.annotation.XmlAccessorType;
25  import javax.xml.bind.annotation.XmlAnyElement;
26  import javax.xml.bind.annotation.XmlElement;
27  import javax.xml.bind.annotation.XmlElementWrapper;
28  import javax.xml.bind.annotation.XmlElements;
29  import javax.xml.bind.annotation.XmlRootElement;
30  import javax.xml.bind.annotation.XmlType;
31  import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
32  
33  import org.apache.commons.lang.StringUtils;
34  import org.kuali.rice.core.api.CoreConstants;
35  import org.kuali.rice.core.api.data.DataType;
36  import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
37  import org.kuali.rice.core.api.mo.ModelBuilder;
38  import org.w3c.dom.Element;
39  
40  /**
41   * @see RemotableAttributeFieldContract for more info.
42   */
43  @XmlRootElement(name = RemotableAttributeField.Constants.ROOT_ELEMENT_NAME)
44  @XmlAccessorType(XmlAccessType.NONE)
45  @XmlType(name = RemotableAttributeField.Constants.TYPE_NAME, propOrder = {
46  		RemotableAttributeField.Elements.NAME,
47  		RemotableAttributeField.Elements.DATA_TYPE,
48  		RemotableAttributeField.Elements.SHORT_LABEL,
49  		RemotableAttributeField.Elements.LONG_LABEL,
50  		RemotableAttributeField.Elements.HELP_SUMMARY,
51  		RemotableAttributeField.Elements.CONSTRAINT_TEXT,
52  		RemotableAttributeField.Elements.HELP_DESCRIPTION,
53  		RemotableAttributeField.Elements.FORCE_UPPERCASE,
54  		RemotableAttributeField.Elements.MIN_LENGTH,
55  		RemotableAttributeField.Elements.MAX_LENGTH,
56  		RemotableAttributeField.Elements.MIN_VALUE,
57  		RemotableAttributeField.Elements.MAX_VALUE,
58  		RemotableAttributeField.Elements.REGEX_CONSTRAINT,
59  		RemotableAttributeField.Elements.REGEX_CONSTRAINT_MSG,
60          RemotableAttributeField.Elements.FORMATTER_NAME,
61  		RemotableAttributeField.Elements.REQUIRED,
62  		RemotableAttributeField.Elements.DEFAULT_VALUES,
63          RemotableAttributeField.Elements.ATTRIBUTE_LOOKUP_SETTINGS,
64  		RemotableAttributeField.Elements.CONTROL,
65  		RemotableAttributeField.Elements.WIDGETS,
66  		CoreConstants.CommonElements.FUTURE_ELEMENTS })
67  public final class RemotableAttributeField extends AbstractDataTransferObject implements RemotableAttributeFieldContract {
68  
69      @XmlElement(name = Elements.NAME, required = true)
70      private final String name;
71  
72      @XmlJavaTypeAdapter(DataType.Adapter.class)
73      @XmlElement(name = Elements.DATA_TYPE, required = false)
74      private final String dataType;
75  
76      @XmlElement(name = Elements.SHORT_LABEL, required = false)
77      private final String shortLabel;
78  
79      @XmlElement(name = Elements.LONG_LABEL, required = false)
80      private final String longLabel;
81  
82      @XmlElement(name = Elements.HELP_SUMMARY, required = false)
83      private final String helpSummary;
84  
85      @XmlElement(name = Elements.CONSTRAINT_TEXT, required = false)
86      private final String constraintText;
87  
88      @XmlElement(name = Elements.HELP_DESCRIPTION, required = false)
89      private final String helpDescription;
90  
91      @XmlElement(name = Elements.FORCE_UPPERCASE, required = false)
92      private final boolean forceUpperCase;
93  
94      @XmlElement(name = Elements.MIN_LENGTH, required = false)
95      private final Integer minLength;
96  
97      @XmlElement(name = Elements.MAX_LENGTH, required = false)
98      private final Integer maxLength;
99  
100     @XmlElement(name = Elements.MIN_VALUE, required = false)
101     private final Double minValue;
102 
103     @XmlElement(name = Elements.MAX_VALUE, required = false)
104     private final Double maxValue;
105 
106     @XmlElement(name = Elements.REGEX_CONSTRAINT, required = false)
107     private final String regexConstraint;
108 
109     @XmlElement(name = Elements.REGEX_CONSTRAINT_MSG, required = false)
110     private final String regexContraintMsg;
111 
112     @XmlElement(name = Elements.FORMATTER_NAME, required = false)
113     private final String formatterName;
114 
115     @XmlElement(name = Elements.REQUIRED, required = false)
116     private final boolean required;
117 
118     @XmlElementWrapper(name = Elements.DEFAULT_VALUES, required = false)
119     @XmlElement(name = Elements.DEFAULT_VALUE, required = false)
120     private final Collection<String> defaultValues;
121 
122     @XmlElement(name = Elements.ATTRIBUTE_LOOKUP_SETTINGS, required = false)
123     private final RemotableAttributeLookupSettings attributeLookupSettings;
124 
125     @XmlElements(value = {
126         @XmlElement(name = RemotableCheckbox.Constants.ROOT_ELEMENT_NAME, type = RemotableCheckbox.class, required = false),
127         @XmlElement(name = RemotableCheckboxGroup.Constants.ROOT_ELEMENT_NAME, type = RemotableCheckboxGroup.class, required = false),
128         @XmlElement(name = RemotableHiddenInput.Constants.ROOT_ELEMENT_NAME, type = RemotableHiddenInput.class, required = false),
129         @XmlElement(name = RemotablePasswordInput.Constants.ROOT_ELEMENT_NAME, type = RemotablePasswordInput.class, required = false),
130         @XmlElement(name = RemotableRadioButtonGroup.Constants.ROOT_ELEMENT_NAME, type = RemotableRadioButtonGroup.class, required = false),
131         @XmlElement(name = RemotableSelect.Constants.ROOT_ELEMENT_NAME, type = RemotableSelect.class, required = false),
132         @XmlElement(name = RemotableTextarea.Constants.ROOT_ELEMENT_NAME, type = RemotableTextarea.class, required = false),
133         @XmlElement(name = RemotableTextInput.Constants.ROOT_ELEMENT_NAME, type = RemotableTextInput.class, required = false)
134     })
135     // this field is defaulted to a RemotableTextInput in constructors and builder
136     // for flexibility, i would have preferred to assign a default value on the client/consumer only but there isn't a practical way to do that
137     private final RemotableAbstractControl control;
138 
139     @XmlElementWrapper(name = Elements.WIDGETS, required = false)
140     @XmlElements(value = {
141         @XmlElement(name = RemotableDatepicker.Constants.ROOT_ELEMENT_NAME, type = RemotableDatepicker.class, required = false),
142         @XmlElement(name = RemotableQuickFinder.Constants.ROOT_ELEMENT_NAME, type = RemotableQuickFinder.class, required = false),
143         @XmlElement(name = RemotableTextExpand.Constants.ROOT_ELEMENT_NAME, type = RemotableTextExpand.class, required = false)
144     })
145     private final Collection<? extends RemotableAbstractWidget> widgets;
146 
147     @SuppressWarnings("unused")
148     @XmlAnyElement
149     private final Collection<Element> _futureElements = null;
150 
151     /**
152      * Should only be invoked by JAXB.
153      */
154     @SuppressWarnings("unused")
155     private RemotableAttributeField() {
156         this.name = null;
157         this.dataType = null;
158         this.shortLabel = null;
159         this.longLabel = null;
160         this.helpSummary = null;
161         this.constraintText = null;
162         this.helpDescription = null;
163         this.forceUpperCase = false;
164         this.minLength = null;
165         this.maxLength = null;
166         this.minValue = null;
167         this.maxValue = null;
168         this.regexConstraint = null;
169         this.regexContraintMsg = null;
170         this.formatterName = null;
171         this.required = false;
172         this.defaultValues = null;
173         this.attributeLookupSettings = null;
174         this.control = RemotableTextInput.Builder.create().build();
175         this.widgets = null;
176     }
177 
178     private RemotableAttributeField(Builder b) {
179         this.name = b.name;
180         if (b.dataType == null) {
181             this.dataType = null;
182         } else {
183             this.dataType = b.dataType.name();
184         }
185         this.shortLabel = b.shortLabel;
186         this.longLabel = b.longLabel;
187         this.helpSummary = b.helpSummary;
188         this.constraintText = b.helpConstraint;
189         this.helpDescription = b.helpDescription;
190         this.forceUpperCase = b.forceUpperCase;
191         this.minLength = b.minLength;
192         this.maxLength = b.maxLength;
193         this.minValue = b.minValue;
194         this.maxValue = b.maxValue;
195         this.regexConstraint = b.regexConstraint;
196         this.regexContraintMsg = b.regexContraintMsg;
197         this.formatterName = b.formatterName;
198         this.required = b.required;
199         if (b.defaultValues == null) {
200             this.defaultValues = Collections.emptyList();
201         } else {
202             List<String> defaultValuesCopy = new ArrayList<String>(b.defaultValues);
203             this.defaultValues = Collections.unmodifiableList(defaultValuesCopy);
204         }
205         if (b.attributeLookupSettings == null) {
206             this.attributeLookupSettings = null;
207         } else {
208             this.attributeLookupSettings = b.attributeLookupSettings.build();
209         }
210         if (b.control == null) {
211             this.control = RemotableTextInput.Builder.create().build();
212         } else {
213             this.control = b.control.build();
214         }
215 
216         final List<RemotableAbstractWidget> temp = new ArrayList<RemotableAbstractWidget>();
217         if (b.widgets != null) {
218             for (RemotableAbstractWidget.Builder attr : b.widgets) {
219                 temp.add(attr.build());
220             }
221         }
222         this.widgets = Collections.unmodifiableList(temp);
223     }
224 
225     @Override
226     public String getName() {
227         return name;
228     }
229 
230     @Override
231     public DataType getDataType() {
232         if (dataType == null) {
233             return null;
234         }
235         return DataType.valueOf(dataType);
236     }
237 
238     @Override
239     public String getShortLabel() {
240         return shortLabel;
241     }
242 
243     @Override
244     public String getLongLabel() {
245         return longLabel;
246     }
247 
248     @Override
249     public String getHelpSummary() {
250         return helpSummary;
251     }
252 
253     @Override
254     public String getConstraintText() {
255         return constraintText;
256     }
257 
258     @Override
259     public String getHelpDescription() {
260         return helpDescription;
261     }
262 
263     @Override
264     public boolean isForceUpperCase() {
265         return forceUpperCase;
266     }
267 
268     @Override
269     public Integer getMinLength() {
270         return minLength;
271     }
272 
273     @Override
274     public Integer getMaxLength() {
275         return maxLength;
276     }
277 
278     @Override
279     public Double getMinValue() {
280         return minValue;
281     }
282 
283     @Override
284     public Double getMaxValue() {
285         return maxValue;
286     }
287 
288     @Override
289     public String getRegexConstraint() {
290         return regexConstraint;
291     }
292 
293     @Override
294     public String getRegexContraintMsg() {
295         return regexContraintMsg;
296     }
297 
298     @Override
299     public String getFormatterName() {
300         return formatterName;
301     }
302     @Override
303     public boolean isRequired() {
304         return required;
305     }
306 
307     @Override
308     public Collection<String> getDefaultValues() {
309         return defaultValues;
310     }
311 
312     @Override
313     public RemotableControlContract getControl() {
314         return control;
315     }
316 
317     @Override
318     public Collection<? extends RemotableAbstractWidget> getWidgets() {
319         return widgets;
320     }
321 
322     @Override
323     public AttributeLookupSettings getAttributeLookupSettings() {
324         return attributeLookupSettings;
325     }
326 
327     /**
328      * Utility method to search a collection of attribute fields and returns
329      * a field for a give attribute name.
330      *
331      * @param attributeName the name of the attribute to search for.  Cannot be blank or null.
332      * @param fields cannot be null.
333      *
334      * @return the attribute field or null if not found.
335      */
336     public static RemotableAttributeField findAttribute(String attributeName, Collection<RemotableAttributeField> fields) {
337         if (StringUtils.isBlank(attributeName)) {
338             throw new IllegalArgumentException("attributeName is blank");
339         }
340 
341         if (fields == null) {
342             throw new IllegalArgumentException("errors is null");
343         }
344 
345         for (RemotableAttributeField field : fields) {
346             if (attributeName.equals(field.getName())) {
347                 return field;
348             }
349         }
350         return null;
351     }
352     
353     public static final class Builder implements RemotableAttributeFieldContract, ModelBuilder {
354         private String name;
355         private DataType dataType;
356         private String shortLabel;
357         private String longLabel;
358 
359         private String helpSummary;
360         private String helpConstraint;
361         private String helpDescription;
362 
363         private boolean forceUpperCase;
364 
365         private Integer minLength;
366         private Integer maxLength;
367 
368         private Double minValue;
369         private Double maxValue;
370         private String regexConstraint;
371         private String regexContraintMsg;
372 
373         private String formatterName;
374         private boolean required;
375 
376         private Collection<String> defaultValues = new ArrayList<String>();
377         private RemotableAttributeLookupSettings.Builder attributeLookupSettings;
378         private RemotableAbstractControl.Builder control =  RemotableTextInput.Builder.create();
379 
380         private Collection<RemotableAbstractWidget.Builder> widgets = new ArrayList<RemotableAbstractWidget.Builder>();
381 
382         private Builder(String name) {
383             setName(name);
384         }
385 
386         public static Builder create(String name) {
387             return new Builder(name);
388         }
389 
390         public static Builder create(RemotableAttributeFieldContract field) {
391             if (field == null) {
392                 throw new IllegalArgumentException("field was null");
393             }
394 
395             Builder b = new Builder(field.getName());
396             b.setDataType(field.getDataType());
397             b.setShortLabel(field.getShortLabel());
398             b.setLongLabel(field.getLongLabel());
399             b.setHelpSummary(field.getHelpSummary());
400             b.setConstraintText(field.getConstraintText());
401             b.setHelpDescription(field.getHelpDescription());
402             b.setForceUpperCase(field.isForceUpperCase());
403             b.setMinLength(field.getMinLength());
404             b.setMaxLength(field.getMaxLength());
405             b.setMinValue(field.getMinValue());
406             b.setMaxValue(field.getMaxValue());
407             b.setRegexConstraint(field.getRegexConstraint());
408             b.setRegexContraintMsg(field.getRegexContraintMsg());
409             b.setFormatterName(field.getFormatterName());
410             b.setRequired(field.isRequired());
411             b.setDefaultValues(field.getDefaultValues());
412             if (field.getAttributeLookupSettings() != null) {
413                 b.setAttributeLookupSettings(RemotableAttributeLookupSettings.Builder.create(
414                         field.getAttributeLookupSettings()));
415             }
416             if (field.getControl() != null) {
417                 b.setControl(ControlCopy.toBuilder(field.getControl()));
418             }
419 
420             final List<RemotableAbstractWidget.Builder> temp = new ArrayList<RemotableAbstractWidget.Builder>();
421             if (field.getWidgets() != null) {
422                 for (RemotableWidgetContract w : field.getWidgets()) {
423                     temp.add(WidgetCopy.toBuilder(w));
424                 }
425             }
426             b.setWidgets(temp);
427 
428             return b;
429         }
430 
431         @Override
432         public String getName() {
433             return name;
434         }
435 
436         public void setName(String name) {
437             if (StringUtils.isBlank(name)) {
438                 throw new IllegalArgumentException("name is blank");
439             }
440 
441             this.name = name;
442         }
443 
444         @Override
445         public DataType getDataType() {
446             return dataType;
447         }
448 
449         public void setDataType(DataType dataType) {
450             this.dataType = dataType;
451         }
452 
453         @Override
454         public String getShortLabel() {
455             return shortLabel;
456         }
457 
458         public void setShortLabel(String shortLabel) {
459             this.shortLabel = shortLabel;
460         }
461 
462         @Override
463         public String getLongLabel() {
464             return longLabel;
465         }
466 
467         public void setLongLabel(String longLabel) {
468             this.longLabel = longLabel;
469         }
470 
471         @Override
472         public String getHelpSummary() {
473             return helpSummary;
474         }
475 
476         public void setHelpSummary(String helpSummary) {
477             this.helpSummary = helpSummary;
478         }
479 
480         @Override
481         public String getConstraintText() {
482             return helpConstraint;
483         }
484 
485         public void setConstraintText(String helpConstraint) {
486             this.helpConstraint = helpConstraint;
487         }
488 
489         @Override
490         public String getHelpDescription() {
491             return helpDescription;
492         }
493 
494         public void setHelpDescription(String helpDescription) {
495             this.helpDescription = helpDescription;
496         }
497 
498         @Override
499         public boolean isForceUpperCase() {
500             return forceUpperCase;
501         }
502 
503         public void setForceUpperCase(boolean forceUpperCase) {
504             this.forceUpperCase = forceUpperCase;
505         }
506 
507         @Override
508         public Integer getMinLength() {
509             return minLength;
510         }
511 
512         public void setMinLength(Integer minLength) {
513             if (minLength != null && minLength < 1) {
514                 throw new IllegalArgumentException("minLength was < 1");
515             }
516             
517             this.minLength = minLength;
518         }
519 
520         @Override
521         public Integer getMaxLength() {
522             return maxLength;
523         }
524 
525         public void setMaxLength(Integer maxLength) {
526             if (maxLength != null && maxLength < 1) {
527                 throw new IllegalArgumentException("maxLength was < 1");
528             }
529             
530             this.maxLength = maxLength;
531         }
532 
533         @Override
534         public Double getMinValue() {
535             return minValue;
536         }
537 
538         public void setMinValue(Double minValue) {
539             this.minValue = minValue;
540         }
541 
542         @Override
543         public Double getMaxValue() {
544             return maxValue;
545         }
546 
547         public void setMaxValue(Double maxValue) {
548             this.maxValue = maxValue;
549         }
550 
551         @Override
552         public String getRegexConstraint() {
553             return regexConstraint;
554         }
555 
556         public void setRegexConstraint(String regexConstraint) {
557             this.regexConstraint = regexConstraint;
558         }
559 
560         @Override
561         public String getRegexContraintMsg() {
562             return regexContraintMsg;
563         }
564 
565         public void setRegexContraintMsg(String regexContraintMsg) {
566             this.regexContraintMsg = regexContraintMsg;
567         }
568 
569         @Override
570         public String getFormatterName() {
571            return formatterName;
572         }
573 
574         public void setFormatterName(String formatterName) {
575            this.formatterName = formatterName;
576         }
577 
578         @Override
579         public boolean isRequired() {
580             return required;
581         }
582 
583         public void setRequired(boolean required) {
584             this.required = required;
585         }
586 
587         @Override
588         public Collection<String> getDefaultValues() {
589             return defaultValues;
590         }
591 
592         public void setDefaultValues(Collection<String> defaultValues) {
593             this.defaultValues = defaultValues;
594         }
595 
596         public void addToDefaultValues(String defaultValue) {
597             this.defaultValues.add(defaultValue);
598         }
599 
600         @Override
601         public RemotableAttributeLookupSettings.Builder getAttributeLookupSettings() {
602             return attributeLookupSettings;
603         }
604 
605         public void setAttributeLookupSettings(RemotableAttributeLookupSettings.Builder attributeLookupSettings) {
606             this.attributeLookupSettings = attributeLookupSettings;
607         }
608 
609         @Override
610         public RemotableAbstractControl.Builder getControl() {
611             return control;
612         }
613 
614         public void setControl(RemotableAbstractControl.Builder control) {
615             this.control = control;
616         }
617 
618         @Override
619         public Collection<RemotableAbstractWidget.Builder> getWidgets() {
620             return widgets;
621         }
622 
623         public void setWidgets(Collection<RemotableAbstractWidget.Builder> widgets) {
624             this.widgets = widgets;
625         }
626 
627         @Override
628         public RemotableAttributeField build() {
629             return new RemotableAttributeField(this);
630         }
631     }
632 
633     /**
634      * Defines some internal constants used on this class.
635      */
636     static final class Constants {
637         static final String TYPE_NAME = "AttributeFieldType";
638         final static String ROOT_ELEMENT_NAME = "attributeField";
639     }
640 
641     static final class Elements {
642         static final String NAME = "name";
643         static final String DATA_TYPE = "dataType";
644         static final String SHORT_LABEL = "shortLabel";
645         static final String LONG_LABEL = "longLabel";
646         static final String HELP_SUMMARY = "helpSummary";
647         static final String CONSTRAINT_TEXT = "constraintText";
648         static final String HELP_DESCRIPTION = "helpDescription";
649         static final String FORCE_UPPERCASE = "forceUpperCase";
650         static final String MIN_LENGTH = "minLength";
651         static final String MAX_LENGTH = "maxLength";
652         static final String MIN_VALUE = "minValue";
653         static final String MAX_VALUE = "maxValue";
654         static final String REGEX_CONSTRAINT = "regexConstraint";
655         static final String REGEX_CONSTRAINT_MSG = "regexContraintMsg";
656         static final String FORMATTER_NAME = "formatterName";
657         static final String REQUIRED = "required";
658         static final String DEFAULT_VALUES = "defaultValues";
659         static final String DEFAULT_VALUE = "defaultValue";
660         static final String ATTRIBUTE_LOOKUP_SETTINGS = "attributeLookupSettings";
661         static final String CONTROL = "control";
662         static final String WIDGETS = "widgets";
663     }
664 }