KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > forms > formmodel > AggregateField


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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.apache.cocoon.forms.formmodel;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23
24 import org.apache.cocoon.forms.FormsConstants;
25 import org.apache.cocoon.forms.FormContext;
26 import org.apache.cocoon.forms.formmodel.AggregateFieldDefinition.SplitMapping;
27 import org.apache.cocoon.forms.util.I18nMessage;
28 import org.apache.cocoon.forms.validation.ValidationError;
29 import org.apache.excalibur.xml.sax.XMLizable;
30 import org.apache.oro.text.regex.MatchResult;
31 import org.apache.oro.text.regex.PatternMatcher;
32 import org.apache.oro.text.regex.Perl5Matcher;
33 import org.outerj.expression.ExpressionException;
34
35 /**
36  * An aggregated field allows to represent one value as multiple input fields, or several values
37  * as one field. Hence this widget is a field and a container widget simultaneously.
38  *
39  * <p>Upon submit, it first attempts to read own value from the request, and splits over nested
40  * field widgets using a regular expression. If split fails, this will simply give a validation error.
41  * If own value was not submitted, it attempts to read values for nested field widgets, and combines
42  * theirs values using combine expression.
43  *
44  * <p>To validate this widget, both the validation rules of the nested widgets are
45  * checked, and those of the aggregated field themselves. The validation rules of the aggregated
46  * field can perform checks on the string as entered by the user (e.g. check its total length).
47  *
48  * <p>This field and nested fields can be of any supported type, as long as combine expression
49  * gives result of the correct type, and split regular expression can split string representation
50  * into parts which can be converted to the values of nested fields.
51  *
52  * @version $Id: AggregateField.java 326838 2005-10-20 06:26:53Z sylvain $
53  */

54 public class AggregateField extends Field implements ContainerWidget {
55
56     private static final String JavaDoc AGGREGATEFIELD_EL = "aggregatefield";
57
58     /**
59      * List of nested fields
60      */

61     private List JavaDoc fields = new ArrayList JavaDoc();
62
63     /**
64      * Map of nested fields
65      */

66     private Map JavaDoc fieldsById = new HashMap JavaDoc();
67
68
69     public AggregateField(AggregateFieldDefinition definition) {
70         super(definition);
71     }
72
73     public final AggregateFieldDefinition getAggregateFieldDefinition() {
74         return (AggregateFieldDefinition)getDefinition();
75     }
76
77     public void initialize() {
78         this.selectionList = getAggregateFieldDefinition().getSelectionList();
79     }
80
81     public void addChild(Widget widget) {
82         if (!(widget instanceof Field)) {
83             throw new IllegalArgumentException JavaDoc("AggregateField can only contain fields.");
84         }
85         addField((Field)widget);
86     }
87
88     protected void addField(Field field) {
89         field.setParent(this);
90         fields.add(field);
91         fieldsById.put(field.getId(), field);
92     }
93
94
95     public boolean hasChild(String JavaDoc id) {
96         return this.fieldsById.containsKey(id);
97     }
98
99     public Iterator JavaDoc getChildren() {
100         return fields.iterator();
101     }
102
103     public void readFromRequest(FormContext formContext) {
104         if (!getCombinedState().isAcceptingInputs()) {
105             return;
106         }
107
108         String JavaDoc newEnteredValue = formContext.getRequest().getParameter(getRequestParameterName());
109         if (newEnteredValue != null) {
110             // There is one aggregated entered value. Read it and split it.
111
super.readFromRequest(formContext);
112             if (this.valueState == VALUE_UNPARSED) {
113                 setFieldsValues(enteredValue);
114             }
115         } else {
116             // Check if there are multiple splitted values. Read them and aggregate them.
117
for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
118                 Field field = (Field)i.next();
119                 field.readFromRequest(formContext);
120                 if (field.valueState == VALUE_UNPARSED) {
121                     this.valueState = VALUE_UNPARSED;
122                 }
123             }
124             if (this.valueState == VALUE_UNPARSED) {
125                 combineFields();
126             }
127         }
128     }
129
130     public void setValue(Object JavaDoc newValue) {
131         super.setValue(newValue);
132         if (this.valueState == VALUE_PARSED) {
133             setFieldsValues(enteredValue);
134         }
135     }
136
137     /**
138      * Returns false if all fields have no value.
139      */

140     private boolean fieldsHaveValues() {
141         for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
142             Field field = (Field)i.next();
143             if (field.getValue() != null) {
144                 return true;
145             }
146         }
147         return false;
148     }
149
150     /**
151      * Splits passed value and sets values of all nested fields.
152      * If split fails, resets all fields.
153      */

154     private void setFieldsValues(String JavaDoc value) {
155         if (value == null) {
156             resetFieldsValues();
157         } else {
158             PatternMatcher matcher = new Perl5Matcher();
159             if (matcher.matches(value, getAggregateFieldDefinition().getSplitPattern())) {
160                 MatchResult matchResult = matcher.getMatch();
161                 Iterator JavaDoc iterator = getAggregateFieldDefinition().getSplitMappingsIterator();
162                 while (iterator.hasNext()) {
163                     SplitMapping splitMapping = (SplitMapping)iterator.next();
164                     String JavaDoc result = matchResult.group(splitMapping.getGroup());
165
166                     // Fields can have a non-string datatype, going to the readFromRequest
167
Field field = (Field)fieldsById.get(splitMapping.getFieldId());
168                     field.readFromRequest(result);
169                 }
170             } else {
171                 resetFieldsValues();
172             }
173         }
174     }
175
176     public void combineFields() {
177         try {
178             Object JavaDoc value = getAggregateFieldDefinition().getCombineExpression().evaluate(new ExpressionContextImpl(this, true));
179             super.setValue(value);
180         } catch (CannotYetResolveWarning e) {
181             super.setValue(null);
182         } catch (ExpressionException e) {
183             super.setValue(null);
184         } catch (ClassCastException JavaDoc e) {
185             super.setValue(null);
186         }
187     }
188
189     /**
190      * Sets values of all nested fields to null
191      */

192     private void resetFieldsValues() {
193         for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
194             Field field = (Field)i.next();
195             field.setValue(null);
196         }
197     }
198
199     public boolean validate() {
200         if (!getCombinedState().isValidatingValues()) {
201             this.wasValid = true;
202             return true;
203         }
204
205         if (enteredValue != null && !fieldsHaveValues()) {
206             XMLizable failMessage = getAggregateFieldDefinition().getSplitFailMessage();
207             if (failMessage != null) {
208                 validationError = new ValidationError(failMessage);
209             } else {
210                 validationError = new ValidationError(new I18nMessage("aggregatedfield.split-failed",
211                                                                       new String JavaDoc[] { getAggregateFieldDefinition().getSplitRegexp() },
212                                                                       FormsConstants.I18N_CATALOGUE));
213             }
214             valueState = VALUE_DISPLAY_VALIDATION;
215             this.wasValid = false;
216             return false;
217         }
218
219         // Validate ALL my child fields
220
boolean valid = true;
221         for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
222             Field field = (Field)i.next();
223             if (!field.validate()) {
224                 validationError = field.getValidationError();
225                 valid = false;
226             }
227         }
228         if (!valid) {
229             valueState = VALUE_DISPLAY_VALIDATION;
230             this.wasValid = false;
231             return false;
232         }
233
234         return super.validate();
235     }
236
237     /**
238      * @return "aggregatefield"
239      */

240     public String JavaDoc getXMLElementName() {
241         return AGGREGATEFIELD_EL;
242     }
243
244     public Widget getChild(String JavaDoc id) {
245         return (Widget)fieldsById.get(id);
246     }
247 }
248
Popular Tags