KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > tags > html > RadioButtonGroup


1 /*
2  * Copyright 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  * $Header:$
17  */

18 package org.apache.beehive.netui.tags.html;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import org.apache.beehive.netui.pageflow.ProcessPopulate;
23 import org.apache.beehive.netui.script.common.DataAccessProviderStack;
24 import org.apache.beehive.netui.tags.naming.FormDataNameInterceptor;
25 import org.apache.beehive.netui.tags.naming.IndexedNameInterceptor;
26 import org.apache.beehive.netui.tags.naming.PrefixNameInterceptor;
27 import org.apache.beehive.netui.tags.rendering.StringBuilderRenderAppender;
28 import org.apache.beehive.netui.tags.rendering.TagRenderingBase;
29 import org.apache.beehive.netui.tags.rendering.WriteRenderAppender;
30 import org.apache.beehive.netui.util.Bundle;
31 import org.apache.beehive.netui.util.logging.Logger;
32 import org.apache.beehive.netui.util.tags.GroupOption;
33
34 import javax.servlet.ServletRequest JavaDoc;
35 import javax.servlet.jsp.JspException JavaDoc;
36 import java.util.*;
37
38 /**
39  * Groups a collection of RadioButtonOptions, and handles databinding of their values.
40  *
41  * If RadioButtonGroup uses any Format tags, it must have those tags come before above any nested
42  * RadioButtonOption tags.
43  * @jsptagref.tagdescription Renders a collection of radiobutton options
44  * as <input type="radio"> and handles the data binding of their values.
45  *
46  * <p>The &lt;netui:radioButtonGroup> tag can generate a set of
47  * radiobutton options in two ways:
48  *
49  * <blockquote>
50  * <ol>
51  * <li>they can be dynamically generated by pointing the
52  * &lt;netui:radioButtonGroup> tag at a {@link java.util.HashMap java.util.HashMap}
53  * or String[] object</li>
54  * <li>they can be statically generated by providing a set of children
55  * {@link RadioButtonOption}
56  * tags</li>
57  * </ol>
58  * </blockquote>
59  *
60  * <p><b>Dynamically Generated Radiobutton Options</b>
61  *
62  * <p>You can dynamically generate a set of radionbutton options by
63  * pointing the &lt;netui:radioButtonGroup> tag at a HashMap
64  * (or any object that implements the {@link java.util.Map java.util.Map} interface).
65  *
66  * <p>For example, if you define a HashMap object and get method in the Controller file...
67  *
68  * <pre> public HashMap hashMap = new HashMap();
69  *
70  * protected HashMap getHashMap()
71  * {
72  * return hashMap;
73  * }
74  *
75  * protected void onCreate()
76  * {
77  * hashMap.put("value1", "Display Text 1");
78  * hashMap.put("value2", "Display Text 2");
79  * hashMap.put("value3", "Display Text 3");
80  * }</pre>
81  *
82  * ...point the &lt;netui:radioButtonGroup>
83  * at the Map object using the <code>optionsDataSource</code> attribute.
84  *
85  * <pre> &lt;netui:radioButtonGroup
86  * dataSource="actionForm.selection"
87  * optionsDataSource="${pageFlow.hashMap}"></pre>
88  *
89  * <p>In the generated radiobutton options, the display text and the
90  * submitted value can be made to differ. The HashMap keys will
91  * form the submitted values, while the HashMap entries will form
92  * the display texts.
93  *
94  * <pre> &lt;input type="radio" name="wlw-radio_button_group_key:{actionForm.selection}" value="value1">Display Text 1&lt;/input>
95  * &lt;input type="radio" name="wlw-radio_button_group_key:{actionForm.selection}" value="value2">Display Text 2&lt;/input>
96  * &lt;input type="radio" name="wlw-radio_button_group_key:{actionForm.selection}" value="value3">Display Text 3&lt;/input></pre>
97  *
98  * <p>Note that you can point the &lt;netui:radioButtonGroup> tag at a
99  * String[] object. A set of radiobutton options will be generated,
100  * but there will be no difference between the
101  * display texts and the submitted values.
102  *
103  * <p><b>Statically Generated Radiobutton Options</b></p>
104  *
105  * <p>To statically generate radiobutton options, place a set of &lt;netui:radioButtonOption> tags inside
106  * the &lt;netui:radioButtonGroup> tag.
107  *
108  * <pre> &lt;netui:radioButtonGroup dataSource="actionForm.selection">
109  * &lt;netui:radioButtonOption value="value1">Display Text 1&lt;/netui:radioButtonOption>&lt;br>
110  * &lt;netui:radioButtonOption value="value2">Display Text 2&lt;/netui:radioButtonOption>&lt;br>
111  * &lt;netui:radioButtonOption value="value3">Display Text 3&lt;/netui:radioButtonOption>&lt;br>
112  * &lt;/netui:radioButtonGroup></pre>
113  *
114  * <p><b>Submitting Data</b></p>
115  *
116  * <p>A &lt;netui:radioButtonGroup> is submitted as a String value. Use the <code>dataSource</code> attribute
117  * to submit to a String object.
118  *
119  * <pre> &lt;netui:radioButtonGroup dataSource="actionForm.selection"></pre>
120  *
121  * <p>In this case, the &lt;netui:radioButtonGroup> submits to a String field of a Form Bean.
122  *
123  * <pre> public static class ProcessDataForm extends FormData
124  * {
125  * private String selection;
126  *
127  * public void setSelection(String selection)
128  * {
129  * this.selection = selection;
130  * }
131  *
132  * public String getSelection()
133  * {
134  * return this.selection;
135  * }
136  * }</pre>
137  * @example In this sample, the &lt;netui:radioButtonGroup>
138  * submits data to the Form Bean field <code>preferredColors</code>.
139  *
140  * <pre> &lt;netui:radioButtonGroup
141  * dataSource="actionForm.preferredColors"
142  * optionsDataSource="${pageFlow.colors}" /></pre>
143  *
144  * The <code>optionsDataSource</code> attribute points to a get method for a String[] on the Controller file:
145  *
146  * <pre> String[] colors = new String[] {"Red", "Blue", "Green", "Yellow", "White", "Black"};
147  *
148  * public String[] getColors()
149  * {
150  * return colors;
151  * }</pre>
152  *
153  * This automatically renders the appropriate set of radionbutton options:
154  *
155  * <pre> &lt;input type="radio" name="wlw-radio_button_group_key:{actionForm.preferredColors}" value="Red">Red&lt;/input>
156  * &lt;input type="radio" name="wlw-radio_button_group_key:{actionForm.preferredColors}" value="Blue">Blue&lt;/input>
157  * &lt;input type="radio" name="wlw-radio_button_group_key:{actionForm.preferredColors}" value="Green">Green&lt;/input>
158  * &lt;input type="radio" name="wlw-radio_button_group_key:{actionForm.preferredColors}" value="Yellow">Yellow&lt;/input>
159  * &lt;input type="radio" name="wlw-radio_button_group_key:{actionForm.preferredColors}" value="White">White&lt;/input>
160  * &lt;input type="radio" name="wlw-radio_button_group_key:{actionForm.preferredColors}" value="Black">Black&lt;/input></pre>
161  * @netui:tag name="radioButtonGroup" description="Defines a group of netui:radioButtonOption elements."
162  */

163 public class RadioButtonGroup
164         extends HtmlGroupBaseTag
165 {
166     // @todo: selection may not work with options in repeater.
167
private static final Logger logger = Logger.getInstance(RadioButtonGroup.class);
168
169     public static final String JavaDoc RADIOBUTTONGROUP_KEY = "radio_button_group_key";
170
171     private String JavaDoc _match; // The actual values we will match against, calculated in doStartTag().
172
private String JavaDoc _defaultRadio; //
173
private Object JavaDoc _dynamicAttrs; // The optionsDataSource object
174
private InternalStringBuilder _saveBody; // The body text
175
private WriteRenderAppender _writer;
176
177
178     private static final List _internalNamingChain;
179
180     static
181     {
182         List l = new ArrayList(3);
183         l.add(new FormDataNameInterceptor());
184         l.add(new IndexedNameInterceptor());
185         l.add(new PrefixNameInterceptor(RADIOBUTTONGROUP_KEY));
186         _internalNamingChain = Collections.unmodifiableList(l);
187     }
188
189     static
190     {
191         org.apache.beehive.netui.pageflow.ProcessPopulate.registerPrefixHandler(RADIOBUTTONGROUP_KEY, new RadioButtonGroupPrefixHandler());
192     }
193
194     /**
195      * The handler for naming and indexing the RadioButtonGroup.
196      */

197     public static class RadioButtonGroupPrefixHandler
198             implements org.apache.beehive.netui.pageflow.RequestParameterHandler
199     {
200         public void process(javax.servlet.http.HttpServletRequest JavaDoc request, String JavaDoc key,
201                             String JavaDoc expr, ProcessPopulate.ExpressionUpdateNode node)
202         {
203             if (logger.isDebugEnabled()) {
204                 logger.debug("*********************************************\n" +
205                         "process with key \"" + key + "\" and expression \"" + node.expression + "\"" +
206                         "*********************************************\n");
207             }
208         }
209     }
210
211     public RadioButtonGroup()
212     {
213         super();
214     }
215
216     /**
217      * Return the name of the Tag.
218      */

219     public String JavaDoc getTagName()
220     {
221         return "RadioButtonGroup";
222     }
223
224     /**
225      * Return an <code>ArrayList</code> which represents a chain of <code>INameInterceptor</code>
226      * objects. This method by default returns <code>null</code> and should be overridden
227      * by objects that support naming.
228      * @return an <code>ArrayList</code> that will contain <code>INameInterceptor</code> objects.
229      */

230     protected List getNamingChain()
231     {
232         return _internalNamingChain;
233     }
234
235     /**
236      * Override the default value to return a string or the empty string if the default value results in a
237      * <code>null</code> value.
238      * @return the value returned from <code>super.evaluteDefaultValue</code> or the empty string.
239      */

240     private String JavaDoc evaluateDefaultValue()
241     {
242         Object JavaDoc val = _defaultValue;
243
244         if (val != null)
245             return val.toString();
246         return "";
247     }
248
249     /**
250      * Does the specified value match one of those we are looking for?
251      * @param value Value to be compared
252      */

253     public boolean isMatched(String JavaDoc value, Boolean JavaDoc defaultValue)
254     {
255         // @todo: there isn't a defaultValue for radio button, what should we do here?
256
if (value == null)
257             return false;
258         if (_match != null)
259             return value.equals(_match);
260         if (_defaultRadio != null)
261             return value.equals(_defaultRadio);
262
263         return false;
264     }
265
266     /**
267      * Determine the match for the RadioButtonGroup
268      * @throws JspException if a JSP exception has occurred
269      */

270     public int doStartTag()
271             throws JspException JavaDoc
272     {
273         // evaluate the datasource and disabled state.
274
Object JavaDoc val = evaluateDataSource();
275         if (val != null)
276             _match = val.toString();
277
278         // Store this tag itself as a page attribute
279
pageContext.setAttribute(RADIOBUTTONGROUP_KEY, this);
280         _defaultRadio = evaluateDefaultValue();
281
282         // see if there are errors in the evaluation
283
if (hasErrors())
284             return SKIP_BODY;
285
286         ServletRequest JavaDoc req = pageContext.getRequest();
287         if (_cr == null)
288             _cr = TagRenderingBase.Factory.getConstantRendering(req);
289
290         _writer = new WriteRenderAppender(pageContext);
291         if (isVertical()) {
292             _cr.TABLE(_writer);
293         }
294
295         // if this is a repeater then we shouid prime the pump...
296
_dynamicAttrs = evaluateOptionsDataSource();
297         assert (_dynamicAttrs != null);
298         assert (_dynamicAttrs instanceof Map ||
299                 _dynamicAttrs instanceof Iterator);
300
301         if (_repeater) {
302             if (_dynamicAttrs instanceof Map) {
303                 _dynamicAttrs = ((Map) _dynamicAttrs).entrySet().iterator();
304
305             }
306             if (!(_dynamicAttrs instanceof Iterator)) {
307                 String JavaDoc s = Bundle.getString("Tags_OptionsDSIteratorError");
308                 registerTagError(s, null);
309                 return SKIP_BODY;
310             }
311             while (((Iterator) _dynamicAttrs).hasNext()) {
312                 _repCurItem = ((Iterator) _dynamicAttrs).next();
313                 if (_repCurItem != null)
314                     break;
315             }
316             if (isVertical())
317                 _cr.TR_TD(_writer);
318
319             DataAccessProviderStack.addDataAccessProvider(this, pageContext);
320         }
321         //write(results.toString());
322
// This is basically this is if enough for 5 options
323
_saveBody = new InternalStringBuilder(640);
324         return EVAL_BODY_INCLUDE;
325     }
326
327     /**
328      * Save any body content of this tag, which will generally be the
329      * option(s) representing the values displayed to the user.
330      * @throws JspException if a JSP exception has occurred
331      */

332     public int doAfterBody() throws JspException JavaDoc
333     {
334         StringBuilderRenderAppender writer = new StringBuilderRenderAppender(_saveBody);
335         if (bodyContent != null) {
336             String JavaDoc value = bodyContent.getString();
337             bodyContent.clearBody();
338             if (value == null)
339                 value = "";
340             _saveBody.append(value);
341         }
342
343         if (_repeater) {
344             ServletRequest JavaDoc req = pageContext.getRequest();
345             if (_cr == null)
346                 _cr = TagRenderingBase.Factory.getConstantRendering(req);
347             if (isVertical())
348                 _cr.end_TD_TR(writer);
349
350             while (((Iterator) _dynamicAttrs).hasNext()) {
351                 _repCurItem = ((Iterator) _dynamicAttrs).next();
352                 if (_repCurItem != null) {
353                     _repIdx++;
354                     if (isVertical())
355                         _cr.TR_TD(writer);
356                     return EVAL_BODY_AGAIN;
357                 }
358             }
359         }
360
361         return SKIP_BODY;
362     }
363
364     /**
365      * Render the set of RadioButtonOptions.
366      * @throws JspException if a JSP exception has occurred
367      */

368     public int doEndTag() throws JspException JavaDoc
369     {
370         if (hasErrors())
371             return reportAndExit(EVAL_PAGE);
372
373         String JavaDoc idScript = null;
374         String JavaDoc altText = null;
375         char accessKey = 0x00;
376
377         // Remove the page scope attributes we created
378
pageContext.removeAttribute(RADIOBUTTONGROUP_KEY);
379         ServletRequest JavaDoc req = pageContext.getRequest();
380         if (_cr == null)
381             _cr = TagRenderingBase.Factory.getConstantRendering(req);
382
383         //InternalStringBuilder results = new InternalStringBuilder(128);
384
if (_saveBody != null)
385             write(_saveBody.toString());
386
387         // if this is a repeater we output the content during the body processing
388
if (_repeater) {
389             // Render a tag representing the end of our current form
390
if (isVertical())
391                 _cr.end_TABLE(_writer);
392
393             if (idScript != null)
394                 write(idScript);
395
396             //write(results.toString());
397
localRelease();
398             return EVAL_PAGE;
399         }
400
401         // Render a tag representing the end of our current form
402
if (_dynamicAttrs instanceof Map) {
403             Map dynamicRadiosMap = (Map) _dynamicAttrs;
404             Iterator keyIterator = dynamicRadiosMap.keySet().iterator();
405             int idx = 0;
406             while (keyIterator.hasNext()) {
407                 Object JavaDoc optionValue = keyIterator.next();
408                 String JavaDoc optionDisplay = null;
409                 if (dynamicRadiosMap.get(optionValue) != null) {
410                     optionDisplay = dynamicRadiosMap.get(optionValue).toString();
411                 }
412                 else {
413                     optionDisplay = "";
414                 }
415
416                 addOption(_writer, INPUT_RADIO, optionValue.toString(), optionDisplay, idx++, altText, accessKey, _disabled);
417                 if (hasErrors()) {
418                     reportErrors();
419                     localRelease();
420                     return EVAL_PAGE;
421                 }
422                 write("\n");
423
424             }
425         }
426         else {
427             assert(_dynamicAttrs instanceof Iterator);
428
429             Iterator it = (Iterator) _dynamicAttrs;
430             int idx = 0;
431             while (it.hasNext()) {
432                 Object JavaDoc o = it.next();
433                 if (o == null)
434                     continue;
435
436                 if (o instanceof GroupOption) {
437                     GroupOption go = (GroupOption) o;
438                     addOption(_writer, INPUT_RADIO, go.getValue(), go.getName(), idx++, go.getAlt(), go.getAccessKey(), _disabled);
439                 }
440                 else {
441                     String JavaDoc radioValue = o.toString();
442                     addOption(_writer, INPUT_RADIO, radioValue, radioValue, idx++, altText, accessKey, _disabled);
443                 }
444                 if (hasErrors()) {
445                     reportErrors();
446                     localRelease();
447                     return EVAL_PAGE;
448                 }
449                 write("\n");
450             }
451         }
452
453         if (isVertical()) {
454             _cr.end_TABLE(_writer);
455         }
456
457         if (idScript != null)
458             write(idScript);
459
460         //write(results.toString());
461
localRelease();
462         return EVAL_PAGE;
463     }
464
465     /**
466      * Release any acquired resources.
467      */

468     protected void localRelease()
469     {
470         // remove the context allowing binding to container.item during binding
471
if (_repeater)
472             DataAccessProviderStack.removeDataAccessProvider(pageContext);
473
474         super.localRelease();
475
476         _match = null;
477         _defaultRadio = null;
478     }
479 }
480
Popular Tags