KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > struts > faces > renderer > AbstractRenderer


1 /*
2  * Copyright 2002,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
17 package org.apache.struts.faces.renderer;
18
19
20 import java.io.IOException JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.Map JavaDoc;
23
24 import javax.faces.application.FacesMessage;
25 import javax.faces.component.EditableValueHolder;
26 import javax.faces.component.UIComponent;
27 import javax.faces.component.ValueHolder;
28 import javax.faces.context.FacesContext;
29 import javax.faces.context.ResponseWriter;
30 import javax.faces.convert.Converter;
31 import javax.faces.convert.ConverterException;
32 import javax.faces.el.ValueBinding;
33 import javax.faces.render.Renderer;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38
39 /**
40  * <p>Abstract base class for concrete implementations of
41  * <code>javax.faces.render.Renderer</code> for the
42  * <em>Struts-Faces Integration Library</em>.</p>
43  *
44  * @version $Rev: 155883 $ $Date: 2005-03-02 06:03:13 +0000 (Wed, 02 Mar 2005) $
45  */

46
47 public abstract class AbstractRenderer extends Renderer {
48
49
50     // -------------------------------------------------------- Static Variables
51

52
53     private static final Log log =
54     LogFactory.getLog(AbstractRenderer.class);
55
56
57     // -------------------------------------------------------- Renderer Methods
58

59
60     /**
61      * <p>Decode any new state of the specified <code>UIComponent</code>
62      * from the request contained in the specified <code>FacesContext</code>,
63      * and store that state on the <code>UIComponent</code>.</p>
64      *
65      * <p>The default implementation calls <code>setSubmittedValue()</code>
66      * unless this component has a boolean <code>disabled</code> or
67      * <code>readonly</code> attribute that is set to <code>true</code>.</p>
68      *
69      * @param context <code>FacesContext</code> for the current request
70      * @param component <code>UIComponent</code> to be decoded
71      *
72      * @exception NullPointerException if <code>context</code> or
73      * <code>component</code> is <code>null</code>
74      */

75     public void decode(FacesContext context, UIComponent component) {
76
77         // Enforce NPE requirements in the Javadocs
78
if ((context == null) || (component == null)) {
79             throw new NullPointerException JavaDoc();
80         }
81
82         // Disabled or readonly components are not decoded
83
if (isDisabled(component) || isReadOnly(component)) {
84             return;
85         }
86
87         // Save submitted value on EditableValueHolder components
88
if (component instanceof EditableValueHolder) {
89             setSubmittedValue(context, component);
90         }
91         
92     }
93
94
95     /**
96      * <p>Render the beginning of the specified <code>UIComponent</code>
97      * to the output stream or writer associated with the response we are
98      * creating.</p>
99      *
100      * <p>The default implementation calls <code>renderStart()</code> and
101      * <code>renderAttributes()</code>.</p>
102      *
103      * @param context <code>FacesContext</code> for the current request
104      * @param component <code>UIComponent</code> to be decoded
105      *
106      * @exception NullPointerException if <code>context</code> or
107      * <code>component</code> is <code>null</code>
108      *
109      * @exception IOException if an input/output error occurs
110      */

111     public void encodeBegin(FacesContext context, UIComponent component)
112         throws IOException JavaDoc {
113
114         // Enforce NPE requirements in the Javadocs
115
if ((context == null) || (component == null)) {
116             throw new NullPointerException JavaDoc();
117         }
118
119     if (log.isTraceEnabled()) {
120         log.trace("encodeBegin(id=" + component.getId() +
121               ", family=" + component.getFamily() +
122               ", rendererType=" + component.getRendererType() + ")");
123     }
124
125         // Render the element and attributes for this component
126
ResponseWriter writer = context.getResponseWriter();
127         renderStart(context, component, writer);
128         renderAttributes(context, component, writer);
129
130     }
131
132
133     /**
134      * <p>Render the children of the specified <code>UIComponent</code>
135      * to the output stream or writer associated with the response we are
136      * creating.</p>
137      *
138      * <p>The default implementation iterates through the children of
139      * this component and renders them.</p>
140      *
141      * @param context <code>FacesContext</code> for the current request
142      * @param component <code>UIComponent</code> to be decoded
143      *
144      * @exception NullPointerException if <code>context</code> or
145      * <code>component</code> is <code>null</code>
146      *
147      * @exception IOException if an input/output error occurs
148      */

149     public void encodeChildren(FacesContext context, UIComponent component)
150         throws IOException JavaDoc {
151
152         if (context == null || component == null) {
153             throw new NullPointerException JavaDoc();
154         }
155
156     if (log.isTraceEnabled()) {
157         log.trace("encodeChildren(id=" + component.getId() +
158               ", family=" + component.getFamily() +
159               ", rendererType=" + component.getRendererType() + ")");
160     }
161     Iterator JavaDoc kids = component.getChildren().iterator();
162     while (kids.hasNext()) {
163         UIComponent kid = (UIComponent) kids.next();
164         kid.encodeBegin(context);
165         if (kid.getRendersChildren()) {
166         kid.encodeChildren(context);
167         }
168         kid.encodeEnd(context);
169     }
170     if (log.isTraceEnabled()) {
171         log.trace("encodeChildren(id=" + component.getId() + ") end");
172     }
173
174     }
175
176
177     /**
178      * <p>Render the ending of the specified <code>UIComponent</code>
179      * to the output stream or writer associated with the response we are
180      * creating.</p>
181      *
182      * <p>The default implementation calls <code>renderEnd()</code>.</p>
183      *
184      * @param context <code>FacesContext</code> for the current request
185      * @param component <code>UIComponent</code> to be decoded
186      *
187      * @exception NullPointerException if <code>context</code> or
188      * <code>component</code> is <code>null</code>
189      *
190      * @exception IOException if an input/output error occurs
191      */

192     public void encodeEnd(FacesContext context, UIComponent component)
193         throws IOException JavaDoc {
194
195         // Enforce NPE requirements in the Javadocs
196
if ((context == null) || (component == null)) {
197             throw new NullPointerException JavaDoc();
198         }
199
200     if (log.isTraceEnabled()) {
201         log.trace("encodeEnd(id=" + component.getId() +
202               ", family=" + component.getFamily() +
203               ", rendererType=" + component.getRendererType() + ")");
204     }
205
206         // Render the element closing for this component
207
ResponseWriter writer = context.getResponseWriter();
208         renderEnd(context, component, writer);
209
210     }
211
212
213     // --------------------------------------------------------- Package Methods
214

215
216     // ------------------------------------------------------- Protected Methods
217

218
219     /**
220      * <p>Render nested child components by invoking the encode methods
221      * on those components, but only when the <code>rendered</code>
222      * property is <code>true</code>.</p>
223      */

224     protected void encodeRecursive(FacesContext context, UIComponent component)
225         throws IOException JavaDoc {
226
227         // suppress rendering if "rendered" property on the component is
228
// false.
229
if (!component.isRendered()) {
230             return;
231         }
232
233         // Render this component and its children recursively
234
if (log.isTraceEnabled()) {
235         log.trace("encodeRecursive(id=" + component.getId() +
236               ", family=" + component.getFamily() +
237               ", rendererType=" + component.getRendererType() +
238               ") encodeBegin");
239     }
240         component.encodeBegin(context);
241         if (component.getRendersChildren()) {
242         if (log.isTraceEnabled()) {
243         log.trace("encodeRecursive(id=" + component.getId() +
244               ") delegating");
245         }
246             component.encodeChildren(context);
247         } else {
248         if (log.isTraceEnabled()) {
249         log.trace("encodeRecursive(id=" + component.getId() +
250               ") recursing");
251         }
252             Iterator JavaDoc kids = component.getChildren().iterator();
253             while (kids.hasNext()) {
254                 UIComponent kid = (UIComponent) kids.next();
255                 encodeRecursive(context, kid);
256             }
257         }
258     if (log.isTraceEnabled()) {
259         log.trace("encodeRecursive(id=" + component.getId() + ") encodeEnd");
260     }
261         component.encodeEnd(context);
262
263     }
264
265
266     /**
267      * <p>Return <code>true</code> if the specified component is disabled.</p>
268      *
269      * @param component <code>UIComponent</code> to be checked
270      */

271     protected boolean isDisabled(UIComponent component) {
272
273         Object JavaDoc disabled = component.getAttributes().get("disabled");
274         if (disabled == null) {
275             return (false);
276         }
277         if (disabled instanceof String JavaDoc) {
278             return (Boolean.valueOf((String JavaDoc) disabled).booleanValue());
279         } else {
280             return (disabled.equals(Boolean.TRUE));
281         }
282
283     }
284
285
286     /**
287      * <p>Return <code>true</code> if the specified component is read only.</p>
288      *
289      * @param component <code>UIComponent</code> to be checked
290      */

291     protected boolean isReadOnly(UIComponent component) {
292
293         Object JavaDoc readonly = component.getAttributes().get("readonly");
294         if (readonly == null) {
295             return (false);
296         }
297         if (readonly instanceof String JavaDoc) {
298             return (Boolean.valueOf((String JavaDoc) readonly).booleanValue());
299         } else {
300             return (readonly.equals(Boolean.TRUE));
301         }
302
303     }
304
305
306     /**
307      * <p>Render the element attributes for the generated markup related to this
308      * component. Simple renderers that create a single markup element
309      * for this component should override this method and include calls to
310      * to <code>writeAttribute()</code> and <code>writeURIAttribute</code>
311      * on the specified <code>ResponseWriter</code>.</p>
312      *
313      * <p>The default implementation does nothing.</p>
314      *
315      * @param context <code>FacesContext</code> for the current request
316      * @param component <code>EditableValueHolder</code> component whose
317      * submitted value is to be stored
318      * @param writer <code>ResponseWriter</code> to which the element
319      * start should be rendered
320      *
321      * @exception IOException if an input/output error occurs
322      */

323     protected void renderAttributes(FacesContext context, UIComponent component,
324                                     ResponseWriter writer) throws IOException JavaDoc {
325
326     }
327
328
329     /**
330      * <p>Render the element end for the generated markup related to this
331      * component. Simple renderers that create a single markup element
332      * for this component should override this method and include a call
333      * to <code>endElement()</code> on the specified
334      * <code>ResponseWriter</code>.</p>
335      *
336      * <p>The default implementation does nothing.</p>
337      *
338      * @param context <code>FacesContext</code> for the current request
339      * @param component <code>EditableValueHolder</code> component whose
340      * submitted value is to be stored
341      * @param writer <code>ResponseWriter</code> to which the element
342      * start should be rendered
343      *
344      * @exception IOException if an input/output error occurs
345      */

346     protected void renderEnd(FacesContext context, UIComponent component,
347                              ResponseWriter writer) throws IOException JavaDoc {
348
349     }
350
351
352     /**
353      * <p>Render any boolean attributes on the specified list that have
354      * <code>true</code> values on the corresponding attribute of the
355      * specified <code>UIComponent</code>.</p>
356      *
357      * @param context <code>FacesContext</code> for the current request
358      * @param component <code>EditableValueHolder</code> component whose
359      * submitted value is to be stored
360      * @param writer <code>ResponseWriter</code> to which the element
361      * start should be rendered
362      * @param names List of attribute names to be passed through
363      *
364      * @exception IOException if an input/output error occurs
365      */

366     protected void renderBoolean(FacesContext context,
367                                  UIComponent component,
368                                  ResponseWriter writer,
369                                  String JavaDoc names[]) throws IOException JavaDoc {
370
371         if (names == null) {
372             return;
373         }
374         Map JavaDoc attributes = component.getAttributes();
375         boolean flag;
376         Object JavaDoc value;
377         for (int i = 0; i < names.length; i++) {
378             value = attributes.get(names[i]);
379             if (value != null) {
380                 if (value instanceof String JavaDoc) {
381                     flag = Boolean.valueOf((String JavaDoc) value).booleanValue();
382                 } else {
383                     flag = Boolean.valueOf(value.toString()).booleanValue();
384                 }
385                 if (flag) {
386                     writer.writeAttribute(names[i], names[i], names[i]);
387                     flag = false;
388                 }
389             }
390         }
391
392     }
393
394
395     /**
396      * <p>Render any attributes on the specified list directly to the
397      * specified <code>ResponseWriter</code> for which the specified
398      * <code>UIComponent</code> has a non-<code>null</code> attribute value.
399      * This method may be used to "pass through" commonly used attribute
400      * name/value pairs with a minimum of code.</p>
401      *
402      * @param context <code>FacesContext</code> for the current request
403      * @param component <code>EditableValueHolder</code> component whose
404      * submitted value is to be stored
405      * @param writer <code>ResponseWriter</code> to which the element
406      * start should be rendered
407      * @param names List of attribute names to be passed through
408      *
409      * @exception IOException if an input/output error occurs
410      */

411     protected void renderPassThrough(FacesContext context,
412                                      UIComponent component,
413                                      ResponseWriter writer,
414                                      String JavaDoc names[]) throws IOException JavaDoc {
415
416         if (names == null) {
417             return;
418         }
419         Map JavaDoc attributes = component.getAttributes();
420         Object JavaDoc value;
421         for (int i = 0; i < names.length; i++) {
422             value = attributes.get(names[i]);
423             if (value != null) {
424                 if (value instanceof String JavaDoc) {
425                     writer.writeAttribute(names[i], value, names[i]);
426                 } else {
427                     writer.writeAttribute(names[i], value.toString(), names[i]);
428                 }
429             }
430         }
431
432     }
433
434
435     /**
436      * <p>Render the element start for the generated markup related to this
437      * component. Simple renderers that create a single markup element
438      * for this component should override this method and include a call
439      * to <code>startElement()</code> on the specified
440      * <code>ResponseWriter</code>.</p>
441      *
442      * <p>The default implementation does nothing.</p>
443      *
444      * @param context <code>FacesContext</code> for the current request
445      * @param component <code>EditableValueHolder</code> component whose
446      * submitted value is to be stored
447      * @param writer <code>ResponseWriter</code> to which the element
448      * start should be rendered
449      *
450      * @exception IOException if an input/output error occurs
451      */

452     protected void renderStart(FacesContext context, UIComponent component,
453                                ResponseWriter writer) throws IOException JavaDoc {
454
455     }
456
457
458     /**
459      * <p>If a submitted value was included on this request, store it in the
460      * component as appropriate.</p>
461      *
462      * <p>The default implementation determines whether this component
463      * implements <code>EditableValueHolder</code>. If so, it checks for a
464      * request parameter with the same name as the <code>clientId</code>
465      * of this <code>UIComponent</code>. If there is such a parameter, its
466      * value is passed (as a String) to the <code>setSubmittedValue()</code>
467      * method on the <code>EditableValueHolder</code> component.</p>
468      *
469      * @param context <code>FacesContext</code> for the current request
470      * @param component <code>EditableValueHolder</code> component whose
471      * submitted value is to be stored
472      */

473     protected void setSubmittedValue
474         (FacesContext context, UIComponent component) {
475
476         if (!(component instanceof EditableValueHolder)) {
477             return;
478         }
479         String JavaDoc clientId = component.getClientId(context);
480         Map JavaDoc parameters = context.getExternalContext().getRequestParameterMap();
481         if (parameters.containsKey(clientId)) {
482             if (log.isTraceEnabled()) {
483                 log.trace("setSubmittedValue(" + clientId + "," +
484                           (String JavaDoc) parameters.get(clientId));
485             }
486             component.getAttributes().put("submittedValue",
487                                           parameters.get(clientId));
488         }
489
490     }
491
492
493     // --------------------------------------------------------- Private Methods
494

495
496     /**
497      * <p>Decode the current state of the specified UIComponent from the
498      * request contained in the specified <code>FacesContext</code>, and
499      * attempt to convert this state information into an object of the
500      * type equired for this component.</p>
501      *
502      * @param context FacesContext for the request we are processing
503      * @param component UIComponent to be decoded
504      *
505      * @exception NullPointerException if context or component is null
506      */

507     /*
508     public void decode(FacesContext context, UIComponent component) {
509
510         // Enforce NPE requirements in the Javadocs
511         if ((context == null) || (component == null)) {
512             throw new NullPointerException();
513         }
514
515         // Only input components need to be decoded
516         if (!(component instanceof UIInput)) {
517             return;
518         }
519         UIInput input = (UIInput) component;
520
521         // Save the old value for use in generating ValueChangedEvents
522         Object oldValue = input.getValue();
523         if (oldValue instanceof String) {
524             try {
525                 oldValue = getAsObject(context, component, (String) oldValue);
526             } catch (ConverterException e) {
527                 ;
528             }
529         }
530         input.setPrevious(oldValue);
531
532         // Decode and convert (if needed) the new value
533         String clientId = component.getClientId(context);
534         Map map = context.getExternalContext().getRequestParameterMap();
535         String newString = (String) map.get(clientId);
536         Object newValue = null;
537         try {
538             newValue = getAsObject(context, component, newString);
539             input.setValue(newValue);
540             input.setValid(true);
541         } catch (ConverterException e) {
542             input.setValue(newValue);
543             input.setValid(false);
544             addConverterMessage(context, component, e.getMessage());
545         }
546         
547     }
548     */

549
550
551     // --------------------------------------------------------- Package Methods
552

553
554     // ------------------------------------------------------- Protected Methods
555

556
557     /**
558      * <p>Add an error message denoting a conversion failure.</p>
559      *
560      * @param context The <code>FacesContext</code> for this request
561      * @param component The <code>UIComponent</code> that experienced
562      * the conversion failure
563      * @param text The text of the error message
564      */

565     /*
566     protected void addConverterMessage(FacesContext context,
567                                        UIComponent component,
568                                        String text) {
569
570         String clientId = component.getClientId(context);
571         FacesMessage message = new FacesMessage
572             (text,
573              "Conversion error on component '" + clientId + "'");
574         context.addMessage(clientId, message);
575
576     }
577     */

578
579
580     /**
581      * <p>Convert the String representation of this component's value
582      * to the corresponding Object representation. The default
583      * implementation utilizes the <code>getAsObject()</code> method of any
584      * associated <code>Converter</code>.</p>
585      *
586      * @param context The <code>FacesContext</code> for this request
587      * @param component The <code>UIComponent</code> whose value is
588      * being converted
589      * @param value The String representation to be converted
590      *
591      * @exception ConverterException if conversion fails
592      */

593     /*
594     protected Object getAsObject(FacesContext context, UIComponent component,
595                                  String value) throws ConverterException {
596
597         // Identify any Converter associated with this component value
598         ValueBinding vb = component.getValueBinding("value");
599         Converter converter = null;
600         if (component instanceof ValueHolder) {
601             // Acquire explicitly assigned Converter (if any)
602             converter = ((ValueHolder) component).getConverter();
603         }
604         if ((converter == null) && (vb != null)) {
605             Class type = vb.getType(context);
606             if ((type == null) || (type == String.class)) {
607                 return (value); // No conversion required for Strings
608             }
609             // Acquire implicit by-type Converter (if any)
610             converter = context.getApplication().createConverter(type);
611         }
612
613         // Convert the result if we identified a Converter
614         if (converter != null) {
615             return (converter.getAsObject(context, component, value));
616         } else {
617             return (value);
618         }
619
620     }
621     */

622
623
624     /**
625      * <p>Convert the Object representation of this component's value
626      * to the corresponding String representation. The default implementation
627      * utilizes the <code>getAsString()</code> method of any associated
628      * <code>Converter</code>.</p>
629      *
630      * @param context The <code>FacesContext</code> for this request
631      * @param component The <code>UIComponent</code> whose value is
632      * being converted
633      * @param value The Object representation to be converted
634      *
635      * @exception ConverterException if conversion fails
636      */

637     protected String JavaDoc getAsString(FacesContext context, UIComponent component,
638                                  Object JavaDoc value) throws ConverterException {
639
640         // Identify any Converter associated with this component value
641
ValueBinding vb = component.getValueBinding("value");
642         Converter converter = null;
643         if (component instanceof ValueHolder) {
644             // Acquire explicitly assigned Converter (if any)
645
converter = ((ValueHolder) component).getConverter();
646         }
647         if ((converter == null) && (vb != null)) {
648             // Acquire implicit by-type Converter (if any)
649
Class JavaDoc type = vb.getType(context);
650             if (type != null) {
651                 converter = context.getApplication().createConverter(type);
652             }
653         }
654
655         // Convert the result if we identified a Converter
656
if (converter != null) {
657             return (converter.getAsString(context, component, value));
658         } else if (value == null) {
659             return ("");
660         } else if (value instanceof String JavaDoc) {
661             return ((String JavaDoc) value);
662         } else {
663             return (value.toString());
664         }
665
666     }
667
668
669 }
670
Popular Tags