KickJava   Java API By Example, From Geeks To Geeks.

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


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

59 public class AggregateField extends Field {
60
61     /**
62      * List of nested fields
63      */

64     private List JavaDoc fields = new ArrayList JavaDoc();
65
66     /**
67      * Map of nested fields
68      */

69     private Map JavaDoc fieldsById = new HashMap JavaDoc();
70
71
72     public AggregateField(AggregateFieldDefinition definition) {
73         super(definition);
74     }
75
76     public final AggregateFieldDefinition getAggregateFieldDefinition() {
77         return (AggregateFieldDefinition)super.definition;
78     }
79
80     protected void addField(Field field) {
81         field.setParent(this);
82         fields.add(field);
83         fieldsById.put(field.getId(), field);
84     }
85
86     public Iterator JavaDoc getChildren() {
87         return fields.iterator();
88     }
89
90     public void readFromRequest(FormContext formContext) {
91         String JavaDoc newEnteredValue = formContext.getRequest().getParameter(getFullyQualifiedId());
92         if (newEnteredValue != null) {
93             // There is one aggregated entered value. Read it and split it.
94
super.readFromRequest(formContext);
95             if (needsParse) {
96                 setFieldsValues(enteredValue);
97             }
98         } else {
99             // Check if there are multiple splitted values. Read them and aggregate them.
100
boolean needsParse = false;
101             for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
102                 Field field = (Field)i.next();
103                 field.readFromRequest(formContext);
104                 needsParse |= field.needsParse;
105             }
106             if (needsParse) {
107                 combineFields();
108             }
109         }
110     }
111
112     public void setValue(Object JavaDoc newValue) {
113         super.setValue(newValue);
114         if (needsValidate) {
115             setFieldsValues(enteredValue);
116         }
117     }
118
119     /**
120      * Returns false if all fields have no value.
121      */

122     private boolean fieldsHaveValues() {
123         for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
124             Field field = (Field)i.next();
125             if (field.getValue() != null) {
126                 return true;
127             }
128         }
129         return false;
130     }
131
132     /**
133      * Splits passed value and sets values of all nested fields.
134      * If split fails, resets all fields.
135      */

136     private void setFieldsValues(String JavaDoc value) {
137         if (value == null) {
138             resetFieldsValues();
139         } else {
140             PatternMatcher matcher = new Perl5Matcher();
141             if (matcher.matches(value, getAggregateFieldDefinition().getSplitPattern())) {
142                 MatchResult matchResult = matcher.getMatch();
143                 Iterator JavaDoc iterator = getAggregateFieldDefinition().getSplitMappingsIterator();
144                 while (iterator.hasNext()) {
145                     SplitMapping splitMapping = (SplitMapping)iterator.next();
146                     String JavaDoc result = matchResult.group(splitMapping.getGroup());
147
148                     // Fields can have a non-string datatype, going to the readFromRequest
149
Field field = (Field)fieldsById.get(splitMapping.getFieldId());
150                     field.readFromRequest(result);
151                 }
152             } else {
153                 resetFieldsValues();
154             }
155         }
156     }
157
158     public void combineFields() {
159         try {
160             Object JavaDoc value = getAggregateFieldDefinition().getCombineExpression().evaluate(new ExpressionContextImpl(this, true));
161             super.setValue(value);
162         } catch (CannotYetResolveWarning e) {
163             super.setValue(null);
164         } catch (ExpressionException e) {
165             super.setValue(null);
166         } catch (ClassCastException JavaDoc e) {
167             super.setValue(null);
168         }
169     }
170
171     /**
172      * Sets values of all nested fields to null
173      */

174     private void resetFieldsValues() {
175         for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
176             Field field = (Field)i.next();
177             field.setValue(null);
178         }
179     }
180
181     public boolean validate(FormContext formContext) {
182         if ((enteredValue != null) != fieldsHaveValues()) {
183             XMLizable failMessage = getAggregateFieldDefinition().getSplitFailMessage();
184             if (failMessage != null) {
185                 validationError = new ValidationError(failMessage);
186             } else {
187                 validationError = new ValidationError(new I18nMessage("aggregatedfield.split-failed",
188                                                                       new String JavaDoc[] { getAggregateFieldDefinition().getSplitRegexp() },
189                                                                       Constants.I18N_CATALOGUE));
190             }
191             return false;
192         }
193
194         // validate my child fields
195
for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
196             Field field = (Field)i.next();
197             if (!field.validate(formContext)) {
198                 validationError = field.getValidationError();
199                 return false;
200             }
201         }
202
203         return super.validate(formContext);
204     }
205
206
207     private static final String JavaDoc AGGREGATEFIELD_EL = "aggregatefield";
208     private static final String JavaDoc VALUE_EL = "value";
209     private static final String JavaDoc VALIDATION_MSG_EL = "validation-message";
210
211     public void generateSaxFragment(ContentHandler JavaDoc contentHandler, Locale JavaDoc locale) throws SAXException JavaDoc {
212         AttributesImpl aggregatedFieldAttrs = new AttributesImpl();
213         aggregatedFieldAttrs.addCDATAAttribute("id", getFullyQualifiedId());
214         aggregatedFieldAttrs.addCDATAAttribute("required", String.valueOf(getAggregateFieldDefinition().isRequired()));
215         contentHandler.startElement(Constants.WI_NS, AGGREGATEFIELD_EL, Constants.WI_PREFIX_COLON + AGGREGATEFIELD_EL, aggregatedFieldAttrs);
216
217         if (enteredValue != null || value != null) {
218             contentHandler.startElement(Constants.WI_NS, VALUE_EL, Constants.WI_PREFIX_COLON + VALUE_EL, Constants.EMPTY_ATTRS);
219             String JavaDoc stringValue;
220             if (value != null) {
221                 stringValue = getDatatype().convertToString(value, locale);
222             } else {
223                 stringValue = enteredValue;
224             }
225             contentHandler.characters(stringValue.toCharArray(), 0, stringValue.length());
226             contentHandler.endElement(Constants.WI_NS, VALUE_EL, Constants.WI_PREFIX_COLON + VALUE_EL);
227         }
228
229         // validation message element: only present if the value is not valid
230
if (validationError != null) {
231             contentHandler.startElement(Constants.WI_NS, VALIDATION_MSG_EL, Constants.WI_PREFIX_COLON + VALIDATION_MSG_EL, Constants.EMPTY_ATTRS);
232             validationError.generateSaxFragment(contentHandler);
233             contentHandler.endElement(Constants.WI_NS, VALIDATION_MSG_EL, Constants.WI_PREFIX_COLON + VALIDATION_MSG_EL);
234         }
235
236         // generate label, help, hint, etc.
237
definition.generateDisplayData(contentHandler);
238
239         // generate selection list, if any
240
if (selectionList != null) {
241             selectionList.generateSaxFragment(contentHandler, locale);
242         } else if (getFieldDefinition().getSelectionList() != null) {
243             getFieldDefinition().getSelectionList().generateSaxFragment(contentHandler, locale);
244         }
245         contentHandler.endElement(Constants.WI_NS, AGGREGATEFIELD_EL, Constants.WI_PREFIX_COLON + AGGREGATEFIELD_EL);
246     }
247
248     public void generateLabel(ContentHandler JavaDoc contentHandler) throws SAXException JavaDoc {
249         definition.generateLabel(contentHandler);
250     }
251
252     public Widget getWidget(String JavaDoc id) {
253         return (Widget)fieldsById.get(id);
254     }
255 }
256
Popular Tags