View Javadoc

1   /*
2    * $Id: UIBean.java 726715 2008-12-15 15:39:15Z musachy $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.struts2.components;
23  
24  import java.io.Writer;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.LinkedHashMap;
28  import java.util.List;
29  import java.util.Map;
30  
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletResponse;
33  
34  import org.apache.struts2.StrutsConstants;
35  import org.apache.struts2.StrutsException;
36  import org.apache.struts2.util.TextProviderHelper;
37  import org.apache.struts2.components.template.Template;
38  import org.apache.struts2.components.template.TemplateEngine;
39  import org.apache.struts2.components.template.TemplateEngineManager;
40  import org.apache.struts2.components.template.TemplateRenderingContext;
41  import org.apache.struts2.views.annotations.StrutsTagAttribute;
42  import org.apache.struts2.views.util.ContextUtil;
43  
44  import com.opensymphony.xwork2.config.ConfigurationException;
45  import com.opensymphony.xwork2.inject.Inject;
46  import com.opensymphony.xwork2.util.ValueStack;
47  import com.opensymphony.xwork2.util.logging.Logger;
48  import com.opensymphony.xwork2.util.logging.LoggerFactory;
49  
50  /***
51   * UIBean is the standard superclass of all Struts UI componentns.
52   * It defines common Struts and html properties all UI components should present for usage.
53   *
54   * <!-- START SNIPPET: templateRelatedAttributes -->
55   *
56   * <table border="1">
57   *    <thead>
58   *       <tr>
59   *          <td>Attribute</td>
60   *          <td>Theme</td>
61   *          <td>Data Types</td>
62   *          <td>Description</td>
63   *       </tr>
64   *    </thead>
65   *    <tbody>
66   *       <tr>
67   *          <td>templateDir</td>
68   *          <td>n/a</td>
69   *          <td>String</td>
70   *          <td>define the template directory</td>
71   *       </td>
72   *       <tr>
73   *          <td>theme</td>
74   *          <td>n/a</td>
75   *          <td>String</td>
76   *          <td>define the theme name</td>
77   *       </td>
78   *       <tr>
79   *          <td>template</td>
80   *          <td>n/a</td>
81   *          <td>String</td>
82   *          <td>define the template name</td>
83   *       </td>
84   *    </tbody>
85   * </table>
86   *
87   * <!-- END SNIPPET: templateRelatedAttributes -->
88   *
89   * <p/>
90   *
91   * <!-- START SNIPPET: generalAttributes -->
92   *
93   * <table border="1">
94   *    <thead>
95   *       <tr>
96   *          <td>Attribute</td>
97   *          <td>Theme</td>
98   *          <td>Data Types</td>
99   *          <td>Description</td>
100  *       </tr>
101  *    </thead>
102  *    <tbody>
103  *       <tr>
104  *          <td>cssClass</td>
105  *          <td>simple</td>
106  *          <td>String</td>
107  *          <td>define html class attribute</td>
108  *       </tr>
109  *       <tr>
110  *          <td>cssStyle</td>
111  *          <td>simple</td>
112  *          <td>String</td>
113  *          <td>define html style attribute</td>
114  *       </tr>
115  *       <tr>
116  *          <td>cssClass</td>
117  *          <td>simple</td>
118  *          <td>String</td>
119  *          <td>error class attribute</td>
120  *       </tr>
121  *       <tr>
122  *          <td>cssStyle</td>
123  *          <td>simple</td>
124  *          <td>String</td>
125  *          <td>error style attribute</td>
126  *       </tr>
127  *       <tr>
128  *          <td>title</td>
129  *          <td>simple</td>
130  *          <td>String</td>
131  *          <td>define html title attribute</td>
132  *       </tr>
133  *       <tr>
134  *          <td>disabled</td>
135  *          <td>simple</td>
136  *          <td>String</td>
137  *          <td>define html disabled attribute</td>
138  *       </tr>
139  *       <tr>
140  *          <td>label</td>
141  *          <td>xhtml</td>
142  *          <td>String</td>
143  *          <td>define label of form element</td>
144  *       </tr>
145  *       <tr>
146  *          <td>labelPosition</td>
147  *          <td>xhtml</td>
148  *          <td>String</td>
149  *          <td>define label position of form element (top/left), default to left</td>
150  *       </tr>
151  *       <tr>
152  *          <td>requiredposition</td>
153  *          <td>xhtml</td>
154  *          <td>String</td>
155  *          <td>define required label position of form element (left/right), default to right</td>
156  *       </tr>
157  *       <tr>
158  *          <td>name</td>
159  *          <td>simple</td>
160  *          <td>String</td>
161  *          <td>Form Element's field name mapping</td>
162  *       </tr>
163  *       <tr>
164  *          <td>required</td>
165  *          <td>xhtml</td>
166  *          <td>Boolean</td>
167  *          <td>add * to label (true to add false otherwise)</td>
168  *       </tr>
169  *       <tr>
170  *          <td>tabIndex</td>
171  *          <td>simple</td>
172  *          <td>String</td>
173  *          <td>define html tabindex attribute</td>
174  *       </tr>
175  *       <tr>
176  *          <td>value</td>
177  *          <td>simple</td>
178  *          <td>Object</td>
179  *          <td>define value of form element</td>
180  *       </tr>
181  *    </tbody>
182  * </table>
183  *
184  * <!-- END SNIPPET: generalAttributes -->
185  *
186  * <p/>
187  *
188  * <!-- START SNIPPET: javascriptRelatedAttributes -->
189  *
190  * <table border="1">
191  *    <thead>
192  *       <tr>
193  *          <td>Attribute</td>
194  *          <td>Theme</td>
195  *          <td>Data Types</td>
196  *          <td>Description</td>
197  *       </tr>
198  *    </thead>
199  *    <tbody>
200  *       <tr>
201  *          <td>onclick</td>
202  *          <td>simple</td>
203  *          <td>String</td>
204  *          <td>html javascript onclick attribute</td>
205  *       </tr>
206  *       <tr>
207  *          <td>ondblclick</td>
208  *          <td>simple</td>
209  *          <td>String</td>
210  *          <td>html javascript ondbclick attribute</td>
211  *       </tr>
212  *       <tr>
213  *          <td>onmousedown</td>
214  *          <td>simple</td>
215  *          <td>String</td>
216  *          <td>html javascript onmousedown attribute</td>
217  *       </tr>
218  *       <tr>
219  *          <td>onmouseup</td>
220  *          <td>simple</td>
221  *          <td>String</td>
222  *          <td>html javascript onmouseup attribute</td>
223  *       </tr>
224  *       <tr>
225  *          <td>onmouseover</td>
226  *          <td>simple</td>
227  *          <td>String</td>
228  *          <td>html javascript onmouseover attribute</td>
229  *       </tr>
230  *       <tr>
231  *          <td>onmouseout</td>
232  *          <td>simple</td>
233  *          <td>String</td>
234  *          <td>html javascript onmouseout attribute</td>
235  *       </tr>
236  *       <tr>
237  *          <td>onfocus</td>
238  *          <td>simple</td>
239  *          <td>String</td>
240  *          <td>html javascript onfocus attribute</td>
241  *       </tr>
242  *       <tr>
243  *          <td>onblur</td>
244  *          <td>simple</td>
245  *          <td>String</td>
246  *          <td>html javascript onblur attribute</td>
247  *       </tr>
248  *       <tr>
249  *          <td>onkeypress</td>
250  *          <td>simple</td>
251  *          <td>String</td>
252  *          <td>html javascript onkeypress attribute</td>
253  *       </tr>
254  *       <tr>
255  *          <td>onkeyup</td>
256  *          <td>simple</td>
257  *          <td>String</td>
258  *          <td>html javascript onkeyup attribute</td>
259  *       </tr>
260  *       <tr>
261  *          <td>onkeydown</td>
262  *          <td>simple</td>
263  *          <td>String</td>
264  *          <td>html javascript onkeydown attribute</td>
265  *       </tr>
266  *       <tr>
267  *          <td>onselect</td>
268  *          <td>simple</td>
269  *          <td>String</td>
270  *          <td>html javascript onselect attribute</td>
271  *       </tr>
272  *       <tr>
273  *          <td>onchange</td>
274  *          <td>simple</td>
275  *          <td>String</td>
276  *          <td>html javascript onchange attribute</td>
277  *       </tr>
278  *    </tbody>
279  * </table>
280  *
281  * <!-- END SNIPPET: javascriptRelatedAttributes -->
282  *
283  * <p/>
284  *
285  * <!-- START SNIPPET: tooltipattributes -->
286  *
287  * <table border="1">
288  *  <tr>
289  *     <td>Attribute</td>
290  *     <td>Data Type</td>
291  *     <td>Default</td>
292  *     <td>Description</td>
293  *  </tr>
294  *  <tr>
295  *      <td>tooltip</td>
296  *      <td>String</td>
297  *      <td>none</td>
298  *      <td>Set the tooltip of this particular component</td>
299  *  </tr>
300  *  <tr>
301  *      <td>jsTooltipEnabled</td>
302  *      <td>String</td>
303  *      <td>false</td>
304  *      <td>Enable js tooltip rendering</td>
305  *  </tr>
306  *    <tr>
307  *      <td>tooltipIcon</td>
308  *      <td>String</td>
309  *      <td>/struts/static/tooltip/tooltip.gif</td>
310  *      <td>The url to the tooltip icon</td>
311  *   <tr>
312  *      <td>tooltipDelay</td>
313  *      <td>String</td>
314  *      <td>500</td>
315  *      <td>Tooltip shows up after the specified timeout (miliseconds). A behavior similar to that of OS based tooltips.</td>
316  *   </tr>
317  *   <tr>
318  *      <td>key</td>
319  *      <td>simple</td>
320  *      <td>String</td>
321  *      <td>The name of the property this input field represents.  This will auto populate the name, label, and value</td>
322  *   </tr>
323  * </table>
324  *
325  * <!-- END SNIPPET: tooltipattributes -->
326  *
327  *
328  * <!-- START SNIPPET: tooltipdescription -->
329  * <b>tooltipConfig is deprecated, use individual tooltip configuration attributes instead </b>
330  *
331  * Every Form UI component (in xhtml / css_xhtml or any other that extends them) can
332  * have tooltips assigned to them. The Form component's tooltip related attribute, once
333  * defined, will be applied to all form UI components that are created under it unless
334  * explicitly overriden by having the Form UI component itself defined with their own tooltip attribute.
335  *
336  * <p/>
337  *
338  * In Example 1, the textfield will inherit the tooltipDelay and tooltipIconPath attribte from
339  * its containing form. In other words, although it doesn't define a tooltipIconPath
340  * attribute, it will have that attribute inherited from its containing form.
341  *
342  * <p/>
343  *
344  * In Example 2, the  textfield will inherite both the tooltipDelay and
345  * tooltipIconPath attribute from its containing form, but the tooltipDelay
346  * attribute is overriden at the textfield itself. Hence, the textfield actually will
347  * have its tooltipIcon defined as /myImages/myIcon.gif, inherited from its containing form, and
348  * tooltipDelay defined as 5000.
349  *
350  * <p/>
351  *
352  * Example 3, 4 and 5 show different ways of setting the tooltip configuration attribute.<br/>
353  * <b>Example 3:</b> Set tooltip config through the body of the param tag<br/>
354  * <b>Example 4:</b> Set tooltip config through the value attribute of the param tag<br/>
355  * <b>Example 5:</b> Set tooltip config through the tooltip attributes of the component tag<br/>
356  *
357  * <!-- END SNIPPET: tooltipdescription -->
358  *
359  *
360  * <pre>
361  * <!-- START SNIPPET: tooltipexample -->
362  *
363  * &lt;!-- Example 1: --&gt;
364  * &lt;s:form
365  *          tooltipDelay="500"
366  *          tooltipIconPath="/myImages/myIcon.gif" .... &gt;
367  *   ....
368  *     &lt;s:textfield label="Customer Name" tooltip="Enter the customer name" .... /&gt;
369  *   ....
370  * &lt;/s:form&gt;
371  *
372  * &lt;!-- Example 2: --&gt;
373  * &lt;s:form
374  *          tooltipDelay="500"
375  *          tooltipIconPath="/myImages/myIcon.gif" .... &gt;
376  *   ....
377  *     &lt;s:textfield label="Address"
378  *          tooltip="Enter your address"
379  *          tooltipDelay="5000" /&gt;
380  *   ....
381  * &lt;/s:form&gt;
382  *
383  *
384  * &lt;-- Example 3: --&gt;
385  * &lt;s:textfield
386  *        label="Customer Name"
387  *        tooltip="One of our customer Details"&gt;
388  *        &lt;s:param name="tooltipDelay"&gt;
389  *             500
390  *        &lt;/s:param&gt;
391  *        &lt;s:param name="tooltipIconPath"&gt;
392  *             /myImages/myIcon.gif
393  *        &lt;/s:param&gt;
394  * &lt;/s:textfield&gt;
395  *
396  *
397  * &lt;-- Example 4: --&gt;
398  * &lt;s:textfield
399  *          label="Customer Address"
400  *          tooltip="Enter The Customer Address" &gt;
401  *          &lt;s:param
402  *              name="tooltipDelay"
403  *              value="500" /&gt;
404  * &lt;/s:textfield&gt;
405  *
406  *
407  * &lt;-- Example 5: --&gt;
408  * &lt;s:textfield
409  *          label="Customer Telephone Number"
410  *          tooltip="Enter customer Telephone Number"
411  *          tooltipDelay="500"
412  *          tooltipIconPath="/myImages/myIcon.gif" /&gt;
413  *
414  * <!-- END SNIPPET: tooltipexample -->
415  * </pre>
416  *
417  */
418 public abstract class UIBean extends Component {
419     private static final Logger LOG = LoggerFactory.getLogger(UIBean.class);
420 
421     protected HttpServletRequest request;
422     protected HttpServletResponse response;
423 
424     public UIBean(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
425         super(stack);
426         this.request = request;
427         this.response = response;
428         this.templateSuffix = ContextUtil.getTemplateSuffix(stack.getContext());
429     }
430 
431     // The templateSuffic to use, overrides the default one if not null.
432     protected String templateSuffix;
433 
434     // The template to use, overrides the default one.
435     protected String template;
436 
437     // templateDir and theme attributes
438     protected String templateDir;
439     protected String theme;
440 
441     // shortcut, sets label, name, and value
442     protected String key;
443 
444     protected String id;
445     protected String cssClass;
446     protected String cssStyle;
447     protected String cssErrorClass;
448     protected String cssErrorStyle;
449     protected String disabled;
450     protected String label;
451     protected String labelPosition;
452     protected String labelSeparator;
453     protected String requiredposition;
454     protected String name;
455     protected String required;
456     protected String tabindex;
457     protected String value;
458     protected String title;
459 
460     // HTML scripting events attributes
461     protected String onclick;
462     protected String ondblclick;
463     protected String onmousedown;
464     protected String onmouseup;
465     protected String onmouseover;
466     protected String onmousemove;
467     protected String onmouseout;
468     protected String onfocus;
469     protected String onblur;
470     protected String onkeypress;
471     protected String onkeydown;
472     protected String onkeyup;
473     protected String onselect;
474     protected String onchange;
475 
476     // common html attributes
477     protected String accesskey;
478 
479     // javascript tooltip attribute
480     protected String tooltip;
481     protected String tooltipConfig;
482     protected String javascriptTooltip;
483     protected String tooltipDelay;
484     protected String tooltipCssClass;
485     protected String tooltipIconPath;
486 
487     // dynamic attributes
488     protected Map<String,Object> dynamicAttributes = new HashMap<String,Object>();
489 
490     protected String defaultTemplateDir;
491     protected String defaultUITheme;
492     protected TemplateEngineManager templateEngineManager;
493 
494     @Inject(StrutsConstants.STRUTS_UI_TEMPLATEDIR)
495     public void setDefaultTemplateDir(String dir) {
496         this.defaultTemplateDir = dir;
497     }
498 
499     @Inject(StrutsConstants.STRUTS_UI_THEME)
500     public void setDefaultUITheme(String theme) {
501         this.defaultUITheme = theme;
502     }
503 
504     @Inject
505     public void setTemplateEngineManager(TemplateEngineManager mgr) {
506         this.templateEngineManager = mgr;
507     }
508 
509     public boolean end(Writer writer, String body) {
510         evaluateParams();
511         try {
512             super.end(writer, body, false);
513             mergeTemplate(writer, buildTemplateName(template, getDefaultTemplate()));
514         } catch (Exception e) {
515             throw new StrutsException(e);
516         }
517         finally {
518             popComponentStack();
519         }
520 
521         return false;
522     }
523 
524     /***
525      * A contract that requires each concrete UI Tag to specify which template should be used as a default.  For
526      * example, the CheckboxTab might return "checkbox.vm" while the RadioTag might return "radio.vm".  This value
527      * <strong>not</strong> begin with a '/' unless you intend to make the path absolute rather than relative to the
528      * current theme.
529      *
530      * @return The name of the template to be used as the default.
531      */
532     protected abstract String getDefaultTemplate();
533 
534     protected Template buildTemplateName(String myTemplate, String myDefaultTemplate) {
535         String template = myDefaultTemplate;
536 
537         if (myTemplate != null) {
538             template = findString(myTemplate);
539         }
540 
541         String templateDir = getTemplateDir();
542         String theme = getTheme();
543 
544         return new Template(templateDir, theme, template);
545 
546     }
547 
548     protected void mergeTemplate(Writer writer, Template template) throws Exception {
549         final TemplateEngine engine = templateEngineManager.getTemplateEngine(template, templateSuffix);
550         if (engine == null) {
551             throw new ConfigurationException("Unable to find a TemplateEngine for template " + template);
552         }
553 
554         if (LOG.isDebugEnabled()) {
555             LOG.debug("Rendering template " + template);
556         }
557 
558         final TemplateRenderingContext context = new TemplateRenderingContext(template, writer, getStack(), getParameters(), this);
559         engine.renderTemplate(context);
560     }
561 
562     public String getTemplateDir() {
563         String templateDir = null;
564 
565         if (this.templateDir != null) {
566             templateDir = findString(this.templateDir);
567         }
568 
569         // If templateDir is not explicitly given,
570         // try to find attribute which states the dir set to use
571         if ((templateDir == null) || (templateDir.equals(""))) {
572             templateDir = stack.findString("#attr.templateDir");
573         }
574 
575         // Default template set
576         if ((templateDir == null) || (templateDir.equals(""))) {
577             templateDir = defaultTemplateDir;
578         }
579 
580         // Defaults to 'template'
581         if ((templateDir == null) || (templateDir.equals(""))) {
582             templateDir = "template";
583         }
584 
585         return templateDir;
586     }
587 
588     public String getTheme() {
589         String theme = null;
590 
591         if (this.theme != null) {
592             theme = findString(this.theme);
593         }
594 
595         if ( theme == null || theme.equals("") ) {
596             Form form = (Form) findAncestor(Form.class);
597             if (form != null) {
598                 theme = form.getTheme();
599             }
600         }
601 
602         // If theme set is not explicitly given,
603         // try to find attribute which states the theme set to use
604         if ((theme == null) || (theme.equals(""))) {
605             theme = stack.findString("#attr.theme");
606         }
607 
608         // Default theme set
609         if ((theme == null) || (theme.equals(""))) {
610             theme = defaultUITheme;
611         }
612 
613         return theme;
614     }
615 
616     public void evaluateParams() {
617         addParameter("templateDir", getTemplateDir());
618         addParameter("theme", getTheme());
619         addParameter("dynamicAttributes", dynamicAttributes);
620 
621         String name = null;
622         String providedLabel = null;
623 
624         if (this.key != null) {
625 
626             if(this.name == null) {
627                 this.name = key;
628             }
629 
630             if(this.label == null) {
631                 // lookup the label from a TextProvider (default value is the key)
632                 providedLabel = TextProviderHelper.getText(key, key, stack);
633             }
634 
635         }
636 
637         if (this.name != null) {
638             name = findString(this.name);
639             addParameter("name", name);
640         }
641 
642         if (label != null) {
643             addParameter("label", findString(label));
644         } else {
645             if (providedLabel != null) {
646                 // label found via a TextProvider
647                 addParameter("label", providedLabel);
648             }
649         }
650 
651         if (labelSeparator != null) {
652             addParameter("labelseparator", findString(labelSeparator));
653         }
654 
655         if (labelPosition != null) {
656             addParameter("labelposition", findString(labelPosition));
657         }
658 
659         if (requiredposition != null) {
660             addParameter("requiredposition", findString(requiredposition));
661         }
662 
663         if (required != null) {
664             addParameter("required", findValue(required, Boolean.class));
665         }
666 
667         if (disabled != null) {
668             addParameter("disabled", findValue(disabled, Boolean.class));
669         }
670 
671         if (tabindex != null) {
672             addParameter("tabindex", findString(tabindex));
673         }
674 
675         if (onclick != null) {
676             addParameter("onclick", findString(onclick));
677         }
678 
679         if (ondblclick != null) {
680             addParameter("ondblclick", findString(ondblclick));
681         }
682 
683         if (onmousedown != null) {
684             addParameter("onmousedown", findString(onmousedown));
685         }
686 
687         if (onmouseup != null) {
688             addParameter("onmouseup", findString(onmouseup));
689         }
690 
691         if (onmouseover != null) {
692             addParameter("onmouseover", findString(onmouseover));
693         }
694 
695         if (onmousemove != null) {
696             addParameter("onmousemove", findString(onmousemove));
697         }
698 
699         if (onmouseout != null) {
700             addParameter("onmouseout", findString(onmouseout));
701         }
702 
703         if (onfocus != null) {
704             addParameter("onfocus", findString(onfocus));
705         }
706 
707         if (onblur != null) {
708             addParameter("onblur", findString(onblur));
709         }
710 
711         if (onkeypress != null) {
712             addParameter("onkeypress", findString(onkeypress));
713         }
714 
715         if (onkeydown != null) {
716             addParameter("onkeydown", findString(onkeydown));
717         }
718 
719         if (onkeyup != null) {
720             addParameter("onkeyup", findString(onkeyup));
721         }
722 
723         if (onselect != null) {
724             addParameter("onselect", findString(onselect));
725         }
726 
727         if (onchange != null) {
728             addParameter("onchange", findString(onchange));
729         }
730 
731         if (accesskey != null) {
732             addParameter("accesskey", findString(accesskey));
733         }
734 
735         if (cssClass != null) {
736             addParameter("cssClass", findString(cssClass));
737         }
738 
739         if (cssStyle != null) {
740             addParameter("cssStyle", findString(cssStyle));
741         }
742 
743         if (cssErrorClass != null) {
744             addParameter("cssErrorClass", findString(cssErrorClass));
745         }
746 
747         if (cssErrorStyle != null) {
748             addParameter("cssErrorStyle", findString(cssErrorStyle));
749         }
750 
751         if (title != null) {
752             addParameter("title", findString(title));
753         }
754 
755 
756         // see if the value was specified as a parameter already
757         if (parameters.containsKey("value")) {
758             parameters.put("nameValue", parameters.get("value"));
759         } else {
760             if (evaluateNameValue()) {
761                 final Class valueClazz = getValueClassType();
762 
763                 if (valueClazz != null) {
764                     if (value != null) {
765                         addParameter("nameValue", findValue(value, valueClazz));
766                     } else if (name != null) {
767                         String expr = completeExpressionIfAltSyntax(name);
768 
769                         addParameter("nameValue", findValue(expr, valueClazz));
770                     }
771                 } else {
772                     if (value != null) {
773                         addParameter("nameValue", findValue(value));
774                     } else if (name != null) {
775                         addParameter("nameValue", findValue(name));
776                     }
777                 }
778             }
779         }
780 
781         final Form form = (Form) findAncestor(Form.class);
782 
783         // create HTML id element
784         populateComponentHtmlId(form);
785 
786         if (form != null ) {
787             addParameter("form", form.getParameters());
788 
789             if ( name != null ) {
790                 // list should have been created by the form component
791                 List tags = (List) form.getParameters().get("tagNames");
792                 tags.add(name);
793             }
794         }
795 
796 
797         // tooltip & tooltipConfig
798         if (tooltipConfig != null) {
799             addParameter("tooltipConfig", findValue(tooltipConfig));
800         }
801         if (tooltip != null) {
802             addParameter("tooltip", findString(tooltip));
803 
804             Map tooltipConfigMap = getTooltipConfig(this);
805 
806             if (form != null) { // inform the containing form that we need tooltip javascript included
807                 form.addParameter("hasTooltip", Boolean.TRUE);
808 
809                 // tooltipConfig defined in component itseilf will take precedence
810                 // over those defined in the containing form
811                 Map overallTooltipConfigMap = getTooltipConfig(form);
812                 overallTooltipConfigMap.putAll(tooltipConfigMap); // override parent form's tooltip config
813 
814                 for (Iterator i = overallTooltipConfigMap.entrySet().iterator(); i.hasNext(); ) {
815                     Map.Entry entry = (Map.Entry) i.next();
816                     addParameter((String) entry.getKey(), entry.getValue());
817                 }
818             }
819             else {
820                 LOG.warn("No ancestor Form found, javascript based tooltip will not work, however standard HTML tooltip using alt and title attribute will still work ");
821             }
822 
823             //TODO: this is to keep backward compatibility, remove once when tooltipConfig is dropped
824             String  jsTooltipEnabled = (String) getParameters().get("jsTooltipEnabled");
825             if (jsTooltipEnabled != null)
826                 this.javascriptTooltip = jsTooltipEnabled;
827 
828             //TODO: this is to keep backward compatibility, remove once when tooltipConfig is dropped
829             String tooltipIcon = (String) getParameters().get("tooltipIcon");
830             if (tooltipIcon != null)
831                 this.addParameter("tooltipIconPath", tooltipIcon);
832             if (this.tooltipIconPath != null)
833                 this.addParameter("tooltipIconPath", findString(this.tooltipIconPath));
834 
835             //TODO: this is to keep backward compatibility, remove once when tooltipConfig is dropped
836             String tooltipDelayParam = (String) getParameters().get("tooltipDelay");
837             if (tooltipDelayParam != null)
838                 this.addParameter("tooltipDelay", tooltipDelayParam);
839             if (this.tooltipDelay != null)
840                 this.addParameter("tooltipDelay", findString(this.tooltipDelay));
841 
842             if (this.javascriptTooltip != null) {
843                 Boolean jsTooltips = (Boolean) findValue(this.javascriptTooltip, Boolean.class);
844                 //TODO use a Boolean model when tooltipConfig is dropped
845                 this.addParameter("jsTooltipEnabled", jsTooltips.toString());
846 
847                 if (form != null)
848                     form.addParameter("hasTooltip", jsTooltips);
849                 if (this.tooltipCssClass != null)
850                     this.addParameter("tooltipCssClass", findString(this.tooltipCssClass));
851             }
852 
853 
854         }
855 
856         evaluateExtraParams();
857     }
858 
859 	protected String escape(String name) {
860         // escape any possible values that can make the ID painful to work with in JavaScript
861         if (name != null) {
862             return name.replaceAll("[^a-zA-Z0-9_]", "_");
863         } else {
864             return "";
865         }
866     }
867 
868     /***
869      * Ensures an unescaped attribute value cannot be vulnerable to XSS attacks
870      *
871      * @param val The value to check
872      * @return The escaped value
873      */
874     protected String ensureAttributeSafelyNotEscaped(String val) {
875         if (val != null) {
876             return val.replaceAll("\"", "&#34;");
877         } else {
878             return "";
879         }
880     }
881 
882     protected void evaluateExtraParams() {
883     }
884 
885     protected boolean evaluateNameValue() {
886         return true;
887     }
888 
889     protected Class getValueClassType() {
890         return String.class;
891     }
892 
893     public void addFormParameter(String key, Object value) {
894         Form form = (Form) findAncestor(Form.class);
895         if (form != null) {
896             form.addParameter(key, value);
897         }
898     }
899 
900     protected void enableAncestorFormCustomOnsubmit() {
901         Form form = (Form) findAncestor(Form.class);
902         if (form != null) {
903             form.addParameter("customOnsubmitEnabled", Boolean.TRUE);
904         } else {
905             LOG.warn("Cannot find an Ancestor form, custom onsubmit is NOT enabled");
906         }
907     }
908 
909     protected Map getTooltipConfig(UIBean component) {
910         Object tooltipConfigObj = component.getParameters().get("tooltipConfig");
911         Map tooltipConfig = new LinkedHashMap();
912 
913         if (tooltipConfigObj instanceof Map) {
914             // we get this if its configured using
915             // 1] UI component's tooltipConfig attribute  OR
916             // 2] <param name="tooltip" value="" /> param tag value attribute
917 
918             tooltipConfig = new LinkedHashMap((Map)tooltipConfigObj);
919         } else if (tooltipConfigObj instanceof String) {
920 
921             // we get this if its configured using
922             // <param name="tooltipConfig"> ... </param> tag's body
923             String tooltipConfigStr = (String) tooltipConfigObj;
924             String[] tooltipConfigArray = tooltipConfigStr.split("//|");
925 
926             for (int a=0; a<tooltipConfigArray.length; a++) {
927                 String[] configEntry = ((String)tooltipConfigArray[a].trim()).split("=");
928                 String key = configEntry[0].trim();
929                 String value = null;
930                 if (configEntry.length > 1) {
931                     value = configEntry[1].trim();
932                     tooltipConfig.put(key, value);
933                 }
934                 else {
935                     LOG.warn("component "+component+" tooltip config param "+key+" has no value defined, skipped");
936                 }
937             }
938         }
939         if (component.javascriptTooltip != null)
940             tooltipConfig.put("jsTooltipEnabled", component.javascriptTooltip);
941         if (component.tooltipIconPath != null)
942             tooltipConfig.put("tooltipIcon", component.tooltipIconPath);
943         if (component.tooltipDelay != null)
944             tooltipConfig.put("tooltipDelay", component.tooltipDelay);
945         return tooltipConfig;
946     }
947 
948     /***
949      * Create HTML id element for the component and populate this component parmaeter
950      * map. Additionally, a parameter named escapedId is populated which contains the found id value filtered by
951      * {@link #escape(String)}, needed eg. for naming Javascript identifiers based on the id value.
952      *
953      * The order is as follows :-
954      * <ol>
955      *   <li>This component id attribute</li>
956      *   <li>[containing_form_id]_[this_component_name]</li>
957      *   <li>[this_component_name]</li>
958      * </ol>
959      *
960      * @param form
961      */
962     protected void populateComponentHtmlId(Form form) {
963         String tryId;
964         if (id != null) {
965             // this check is needed for backwards compatibility with 2.1.x
966             tryId = findStringIfAltSyntax(id);
967         } else if (form != null) {
968             tryId = form.getParameters().get("id") + "_"
969                     + escape(name != null ? findString(name) : null);
970         } else {
971             tryId = escape(name != null ? findString(name) : null);
972         }
973         addParameter("id", tryId);
974         addParameter("escapedId", escape(tryId));
975     }
976 
977     /***
978      * Get's the id for referencing element.
979      * @return the id for referencing element.
980      */
981     public String getId() {
982         return id;
983     }
984 
985     @StrutsTagAttribute(description="HTML id attribute")
986     public void setId(String id) {
987         if (id != null) {
988             this.id = findString(id);
989         }
990     }
991 
992     @StrutsTagAttribute(description="The template directory.")
993     public void setTemplateDir(String templateDir) {
994         this.templateDir = templateDir;
995     }
996 
997     @StrutsTagAttribute(description="The theme (other than default) to use for rendering the element")
998     public void setTheme(String theme) {
999         this.theme = theme;
1000     }
1001 
1002     public String getTemplate() {
1003         return template;
1004     }
1005 
1006     @StrutsTagAttribute(description="The template (other than default) to use for rendering the element")
1007     public void setTemplate(String template) {
1008         this.template = template;
1009     }
1010 
1011     @StrutsTagAttribute(description="The css class to use for element")
1012     public void setCssClass(String cssClass) {
1013         this.cssClass = cssClass;
1014     }
1015 
1016     @StrutsTagAttribute(description="The css style definitions for element to use")
1017     public void setCssStyle(String cssStyle) {
1018         this.cssStyle = cssStyle;
1019     }
1020 
1021     @StrutsTagAttribute(description="The css error class to use for element")
1022     public void setCssErrorClass(String cssErrorClass) {
1023         this.cssErrorClass = cssErrorClass;
1024     }
1025 
1026     @StrutsTagAttribute(description="The css error style definitions for element to use")
1027     public void setCssErrorStyle(String cssErrorStyle) {
1028         this.cssErrorStyle = cssErrorStyle;
1029     }
1030 
1031     @StrutsTagAttribute(description="Set the html title attribute on rendered html element")
1032     public void setTitle(String title) {
1033         this.title = title;
1034     }
1035 
1036     @StrutsTagAttribute(description="Set the html disabled attribute on rendered html element")
1037     public void setDisabled(String disabled) {
1038         this.disabled = disabled;
1039     }
1040 
1041     @StrutsTagAttribute(description="Label expression used for rendering an element specific label")
1042     public void setLabel(String label) {
1043         this.label = label;
1044     }
1045 
1046     @StrutsTagAttribute(description="String that will be appended to the label", defaultValue=":")
1047     public void setLabelSeparator(String labelseparator) {
1048         this.labelSeparator = labelseparator;
1049     }
1050 
1051     @StrutsTagAttribute(description="Define label position of form element (top/left)")
1052     public void setLabelposition(String labelPosition) {
1053         this.labelPosition = labelPosition;
1054     }
1055 
1056     @StrutsTagAttribute(description="Define required position of required form element (left|right)")
1057     public void setRequiredposition(String requiredposition) {
1058         this.requiredposition = requiredposition;
1059     }
1060 
1061     @StrutsTagAttribute(description="The name to set for element")
1062     public void setName(String name) {
1063         this.name = name;
1064     }
1065 
1066     @StrutsTagAttribute(description="If set to true, the rendered element will indicate that input is required", type="Boolean", defaultValue="false")
1067     public void setRequired(String required) {
1068         this.required = required;
1069     }
1070 
1071     @StrutsTagAttribute(description="Set the html tabindex attribute on rendered html element")
1072     public void setTabindex(String tabindex) {
1073         this.tabindex = tabindex;
1074     }
1075 
1076     @StrutsTagAttribute(description="Preset the value of input element.")
1077     public void setValue(String value) {
1078         this.value = value;
1079     }
1080 
1081     @StrutsTagAttribute(description="Set the html onclick attribute on rendered html element")
1082     public void setOnclick(String onclick) {
1083         this.onclick = onclick;
1084     }
1085 
1086     @StrutsTagAttribute(description="Set the html ondblclick attribute on rendered html element")
1087     public void setOndblclick(String ondblclick) {
1088         this.ondblclick = ondblclick;
1089     }
1090 
1091     @StrutsTagAttribute(description="Set the html onmousedown attribute on rendered html element")
1092     public void setOnmousedown(String onmousedown) {
1093         this.onmousedown = onmousedown;
1094     }
1095 
1096     @StrutsTagAttribute(description="Set the html onmouseup attribute on rendered html element")
1097     public void setOnmouseup(String onmouseup) {
1098         this.onmouseup = onmouseup;
1099     }
1100 
1101     @StrutsTagAttribute(description="Set the html onmouseover attribute on rendered html element")
1102     public void setOnmouseover(String onmouseover) {
1103         this.onmouseover = onmouseover;
1104     }
1105 
1106     @StrutsTagAttribute(description="Set the html onmousemove attribute on rendered html element")
1107     public void setOnmousemove(String onmousemove) {
1108         this.onmousemove = onmousemove;
1109     }
1110 
1111     @StrutsTagAttribute(description="Set the html onmouseout attribute on rendered html element")
1112     public void setOnmouseout(String onmouseout) {
1113         this.onmouseout = onmouseout;
1114     }
1115 
1116     @StrutsTagAttribute(description="Set the html onfocus attribute on rendered html element")
1117     public void setOnfocus(String onfocus) {
1118         this.onfocus = onfocus;
1119     }
1120 
1121     @StrutsTagAttribute(description=" Set the html onblur attribute on rendered html element")
1122     public void setOnblur(String onblur) {
1123         this.onblur = onblur;
1124     }
1125 
1126     @StrutsTagAttribute(description="Set the html onkeypress attribute on rendered html element")
1127     public void setOnkeypress(String onkeypress) {
1128         this.onkeypress = onkeypress;
1129     }
1130 
1131     @StrutsTagAttribute(description="Set the html onkeydown attribute on rendered html element")
1132     public void setOnkeydown(String onkeydown) {
1133         this.onkeydown = onkeydown;
1134     }
1135 
1136     @StrutsTagAttribute(description="Set the html onkeyup attribute on rendered html element")
1137     public void setOnkeyup(String onkeyup) {
1138         this.onkeyup = onkeyup;
1139     }
1140 
1141     @StrutsTagAttribute(description="Set the html onselect attribute on rendered html element")
1142     public void setOnselect(String onselect) {
1143         this.onselect = onselect;
1144     }
1145 
1146     @StrutsTagAttribute(description="Set the html onchange attribute on rendered html element")
1147     public void setOnchange(String onchange) {
1148         this.onchange = onchange;
1149     }
1150 
1151     @StrutsTagAttribute(description="Set the html accesskey attribute on rendered html element")
1152     public void setAccesskey(String accesskey) {
1153         this.accesskey = accesskey;
1154     }
1155 
1156     @StrutsTagAttribute(description="Set the tooltip of this particular component")
1157     public void setTooltip(String tooltip) {
1158         this.tooltip = tooltip;
1159     }
1160 
1161     @StrutsTagAttribute(description="Deprecated. Use individual tooltip configuration attributes instead.")
1162     public void setTooltipConfig(String tooltipConfig) {
1163         this.tooltipConfig = tooltipConfig;
1164     }
1165 
1166     @StrutsTagAttribute(description="Set the key (name, value, label) for this particular component")
1167     public void setKey(String key) {
1168         this.key = key;
1169     }
1170 
1171     @StrutsTagAttribute(description="Use JavaScript to generate tooltips", type="Boolean", defaultValue="false")
1172     public void setJavascriptTooltip(String javascriptTooltip) {
1173         this.javascriptTooltip = javascriptTooltip;
1174     }
1175 
1176     @StrutsTagAttribute(description="CSS class applied to JavaScrip tooltips", defaultValue="StrutsTTClassic")
1177     public void setTooltipCssClass(String tooltipCssClass) {
1178         this.tooltipCssClass = tooltipCssClass;
1179     }
1180 
1181     @StrutsTagAttribute(description="Delay in milliseconds, before showing JavaScript tooltips ",
1182         defaultValue="Classic")
1183     public void setTooltipDelay(String tooltipDelay) {
1184         this.tooltipDelay = tooltipDelay;
1185     }
1186 
1187     @StrutsTagAttribute(description="Icon path used for image that will have the tooltip")
1188     public void setTooltipIconPath(String tooltipIconPath) {
1189         this.tooltipIconPath = tooltipIconPath;
1190     }
1191 
1192     public void setDynamicAttributes(Map<String,Object> dynamicAttributes) {
1193         this.dynamicAttributes = dynamicAttributes;
1194     }
1195 }