KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.util.HashMap JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.Locale JavaDoc;
21 import java.util.Map JavaDoc;
22 import java.util.StringTokenizer JavaDoc;
23
24 import org.apache.cocoon.woody.Constants;
25 import org.apache.cocoon.woody.FormContext;
26 import org.apache.cocoon.woody.event.FormHandler;
27 import org.apache.cocoon.woody.event.ProcessingPhase;
28 import org.apache.cocoon.woody.event.ProcessingPhaseEvent;
29 import org.apache.cocoon.woody.event.ProcessingPhaseListener;
30 import org.apache.cocoon.woody.event.WidgetEvent;
31 import org.apache.cocoon.woody.event.WidgetEventMulticaster;
32 import org.apache.cocoon.xml.AttributesImpl;
33 import org.apache.commons.collections.list.CursorableLinkedList;
34 import org.xml.sax.ContentHandler JavaDoc;
35 import org.xml.sax.SAXException JavaDoc;
36
37 /**
38  * A widget that serves as a container for other widgets, the top-level widget in
39  * a form description file.
40  *
41  * @author Bruno Dumon
42  * @author <a HREF="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
43  * @version CVS $Id: Form.java 30932 2004-07-29 17:35:38Z vgritsenko $
44  */

45 public class Form extends AbstractContainerWidget {
46     
47     private Boolean JavaDoc endProcessing;
48     private Locale JavaDoc locale = Locale.getDefault();
49     private CursorableLinkedList events;
50 // private FormDefinition definition;
51
private FormHandler formHandler;
52     private Widget submitWidget;
53     private ProcessingPhase phase = ProcessingPhase.LOAD_MODEL;
54     private boolean isValid = false;
55     private ProcessingPhaseListener listener;
56     private Map JavaDoc attributes;
57
58     public Form(FormDefinition definition) {
59         super(definition);
60         setLocation(definition.getLocation());
61     }
62
63     /**
64      * Events produced by child widgets should not be fired immediately, but queued in order to ensure
65      * an overall consistency of the widget tree before being handled.
66      *
67      * @param event the event to queue
68      */

69     public void addWidgetEvent(WidgetEvent event) {
70         
71         if (this.events == null) {
72             this.events = new CursorableLinkedList();
73         }
74         
75         // FIXME: limit the number of events to detect recursive event loops ?
76
this.events.add(event);
77     }
78     
79     /**
80      * Fire the widget events that have been queued. Note that event handling can fire new
81      * events.
82      */

83     private void fireWidgetEvents() {
84         if (this.events != null) {
85             CursorableLinkedList.Cursor cursor = this.events.cursor();
86             while(cursor.hasNext()) {
87                 WidgetEvent event = (WidgetEvent)cursor.next();
88                 event.getSourceWidget().broadcastEvent(event);
89                 if (formHandler != null)
90                     formHandler.handleEvent(event);
91             }
92             cursor.close();
93         
94             this.events.clear();
95         }
96     }
97
98     /**
99      * Get the locale to be used to process this form.
100      *
101      * @return the form's locale.
102      */

103     public Locale JavaDoc getLocale() {
104         return this.locale;
105     }
106
107     /**
108      * Get the widget that triggered the current processing. Note that it can be any widget, and
109      * not necessarily an action or a submit.
110      *
111      * @return the widget that submitted this form.
112      */

113     public Widget getSubmitWidget() {
114         return this.submitWidget;
115     }
116     
117     /**
118      * Set the widget that triggered the current form processing.
119      *
120      * @param widget the widget
121      */

122     public void setSubmitWidget(Widget widget) {
123         if (this.submitWidget != null && this.submitWidget != widget) {
124             throw new IllegalStateException JavaDoc("SubmitWidget can only be set once.");
125         }
126         if (!(widget instanceof Action)) {
127             endProcessing(true);
128         }
129         this.submitWidget = widget;
130     }
131
132     public void setFormHandler(FormHandler formHandler) {
133         this.formHandler = formHandler;
134     }
135
136 // TODO: going through the form for load and save ensures state consistency. To we add this or
137
// keep the binding strictly separate ?
138
// public void load(Object data, Binding binding) {
139
// if (this.phase != ProcessingPhase.LOAD_MODEL) {
140
// throw new IllegalStateException("Cannot load form in phase " + this.phase);
141
// }
142
// binding.loadFormFromModel(this, data);
143
// }
144
//
145
// public void save(Object data, Binding binding) throws BindingException {
146
// if (this.phase != ProcessingPhase.VALIDATE) {
147
// throw new IllegalStateException("Cannot save model in phase " + this.phase);
148
// }
149
//
150
// if (!isValid()) {
151
// throw new IllegalStateException("Cannot save an invalid form.");
152
// }
153
// this.phase = ProcessingPhase.SAVE_MODEL;
154
// binding.saveFormToModel(this, data);
155
// }
156

157     public void addProcessingPhaseListener(ProcessingPhaseListener listener) {
158         this.listener = WidgetEventMulticaster.add(this.listener, listener);
159     }
160     
161     public void removeProcessingPhaseListener(ProcessingPhaseListener listener) {
162         this.listener = WidgetEventMulticaster.remove(this.listener, listener);
163     }
164
165     /**
166      * Processes a form submit. If the form is finished, i.e. the form should not be redisplayed to the user,
167      * then this method returns true, otherwise it returns false. To know if the form was sucessfully
168      * validated, use the {@link #isValid()} method.
169      * <p>
170      * Form processing consists in multiple steps:
171      * <ul>
172      * <li>all widgets read their value from the request (i.e.
173      * {@link #readFromRequest(FormContext)} is called recursively on
174      * the whole widget tree)
175      * <li>if there is an action event, call the FormHandler
176      * <li>perform validation.
177      * </ul>
178      * This processing can be interrupted by the widgets (or their event listeners) by calling
179      * {@link #endProcessing(boolean)}.
180      */

181     public boolean process(FormContext formContext) {
182         
183         // Fire the binding phase events
184
fireWidgetEvents();
185         
186         // setup processing
187
this.submitWidget = null;
188         this.locale = formContext.getLocale();
189         this.endProcessing = null;
190         this.isValid = false;
191         
192         // Notify the end of the current phase
193
if (this.listener != null) {
194             this.listener.phaseEnded(new ProcessingPhaseEvent(this, this.phase));
195         }
196         
197         this.phase = ProcessingPhase.READ_FROM_REQUEST;
198         // Find the submit widget, if not an action
199
this.submitWidget = null;
200         String JavaDoc submitId = formContext.getRequest().getParameter("woody_submit_id");
201         if (submitId != null && submitId.length() > 0) {
202             StringTokenizer JavaDoc stok = new StringTokenizer JavaDoc(submitId, ".");
203             Widget submit = this;
204             while (stok.hasMoreTokens()) {
205                 submit = submit.getWidget(stok.nextToken());
206                 if (submit == null) {
207                     throw new IllegalArgumentException JavaDoc("Invalid submit id (no such widget): " + submitId);
208                 }
209             }
210             
211             setSubmitWidget(submit);
212         }
213         
214         doReadFromRequest(formContext);
215         fireWidgetEvents();
216         
217         // Notify the end of the current phase
218
if (this.listener != null) {
219             this.listener.phaseEnded(new ProcessingPhaseEvent(this, this.phase));
220         }
221
222         if (this.endProcessing != null) {
223             return this.endProcessing.booleanValue();
224         }
225
226         // Validate the form
227
this.phase = ProcessingPhase.VALIDATE;
228         this.isValid = doValidate(formContext);
229         
230         if (this.endProcessing != null) {
231             return this.endProcessing.booleanValue();
232         }
233         
234         // Notify the end of the current phase
235
if (this.listener != null) {
236             this.listener.phaseEnded(new ProcessingPhaseEvent(this, this.phase));
237         }
238         
239         if (this.endProcessing != null) {
240             // De-validate the form if one of the listeners asked to end the processing
241
// This allows for additional application-level validation.
242
this.isValid = false;
243             return this.endProcessing.booleanValue();
244         }
245         
246         return this.isValid;
247     }
248     
249     /**
250      * End the current form processing after the current phase.
251      *
252      * @param redisplayForm indicates if the form should be redisplayed to the user.
253      */

254     public void endProcessing(boolean redisplayForm) {
255         this.endProcessing = new Boolean JavaDoc(!redisplayForm);
256     }
257     
258     /**
259      * Was form validation successful ?
260      *
261      * @return <code>true</code> if the form was successfully validated.
262      */

263     public boolean isValid() {
264         return this.isValid;
265     }
266
267     public void readFromRequest(FormContext formContext) {
268         throw new UnsupportedOperationException JavaDoc("Please use Form.process()");
269     }
270
271     private void doReadFromRequest(FormContext formContext) {
272         // let all individual widgets read their value from the request object
273
super.readFromRequest(formContext);
274     }
275
276     public boolean validate(FormContext formContext) {
277         throw new UnsupportedOperationException JavaDoc("Please use Form.process()");
278     }
279
280     public boolean doValidate(FormContext formContext) {
281         return super.validate(formContext);
282     }
283     
284     public Object JavaDoc getAttribute(String JavaDoc name) {
285         return this.attributes == null ? null : this.attributes.get(name);
286     }
287     
288     public void setAttribute(String JavaDoc name, Object JavaDoc value) {
289         if (this.attributes == null) {
290             this.attributes = new HashMap JavaDoc();
291         }
292         
293         this.attributes.put(name, value);
294     }
295     
296     public void removeAttribute(String JavaDoc name) {
297         if (this.attributes != null) {
298             this.attributes.remove(name);
299         }
300     }
301
302     private static final String JavaDoc FORM_EL = "form";
303     private static final String JavaDoc CHILDREN_EL = "children";
304
305     public void generateSaxFragment(ContentHandler JavaDoc contentHandler, Locale JavaDoc locale) throws SAXException JavaDoc {
306         AttributesImpl formAttrs = new AttributesImpl();
307         formAttrs.addCDATAAttribute("id", definition.getId());
308         contentHandler.startElement(Constants.WI_NS, FORM_EL, Constants.WI_PREFIX_COLON + FORM_EL, Constants.EMPTY_ATTRS);
309         definition.generateLabel(contentHandler);
310
311         contentHandler.startElement(Constants.WI_NS, CHILDREN_EL, Constants.WI_PREFIX_COLON + CHILDREN_EL, Constants.EMPTY_ATTRS);
312         Iterator JavaDoc widgetIt = widgets.iterator();
313         while (widgetIt.hasNext()) {
314             Widget widget = (Widget)widgetIt.next();
315             widget.generateSaxFragment(contentHandler, locale);
316         }
317         contentHandler.endElement(Constants.WI_NS, CHILDREN_EL, Constants.WI_PREFIX_COLON + CHILDREN_EL);
318
319         contentHandler.endElement(Constants.WI_NS, FORM_EL, Constants.WI_PREFIX_COLON + FORM_EL);
320     }
321
322     public void generateLabel(ContentHandler JavaDoc contentHandler) throws SAXException JavaDoc {
323         definition.generateLabel(contentHandler);
324     }
325 }
326
Popular Tags