View Javadoc

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.component;
18  
19  
20  import java.util.Map;
21  import javax.faces.component.UIForm;
22  import javax.faces.context.FacesContext;
23  import javax.faces.el.ValueBinding;
24  import javax.servlet.http.HttpSession;
25  import org.apache.commons.beanutils.DynaBean;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.struts.Globals;
29  import org.apache.struts.action.ActionForm;
30  import org.apache.struts.action.ActionServlet;
31  import org.apache.struts.action.DynaActionFormClass;
32  import org.apache.struts.config.ActionConfig;
33  import org.apache.struts.config.FormBeanConfig;
34  import org.apache.struts.config.ModuleConfig;
35  import org.apache.struts.util.RequestUtils;
36  
37  
38  /***
39   * <p><strong>FormComponent</strong> is a specialized subclass of
40   * <code>javax.faces.component.UIForm</code> that supports automatic
41   * creation of form beans in request or session scope.</p>
42   *
43   * @version $Rev: 421138 $ $Date: 2006-07-11 22:41:40 -0700 (Tue, 11 Jul 2006) $
44   */
45  public class FormComponent extends UIForm {
46  
47  
48      // -------------------------------------------------------- Static Variables
49  
50  
51      /***
52       * <p>The <code>Log</code> instance for this class.</p>
53       */
54      protected static Log log = LogFactory.getLog(FormComponent.class);
55  
56  
57      // ------------------------------------------------------ Instance Variables
58  
59  
60      private String action = null;
61      private String enctype = null;
62      private String focus = null;
63      private String focusIndex = null;
64      private String onreset = null;
65      private String onsubmit = null;
66      private String style = null;
67      private String styleClass = null;
68      private String target = null;
69  
70  
71      // ---------------------------------------------------- Component Properties
72  
73  
74      /***
75       * <p>Return the Struts action path to which this form should be submitted.
76       * </p>
77       */
78      public String getAction() {
79  
80          if (this.action != null) {
81              return (this.action);
82          }
83          ValueBinding vb = getValueBinding("action");
84          if (vb != null) {
85              return ((String) vb.getValue(getFacesContext()));
86          } else {
87              return (null);
88          }
89  
90      }
91  
92  
93      /***
94       * <p>Set the Struts action to which this form should be submitted.</p>
95       *
96       * @param action The new action path
97       */
98      public void setAction(String action) {
99  
100         this.action = action;
101 
102     }
103 
104 
105     /***
106      * <p>Return the encoding type for this form submit.</p>
107      */
108     public String getEnctype() {
109 
110         if (this.enctype != null) {
111             return (this.enctype);
112         }
113         ValueBinding vb = getValueBinding("enctype");
114         if (vb != null) {
115             return ((String) vb.getValue(getFacesContext()));
116         } else {
117             return (null);
118         }
119 
120     }
121 
122 
123     /***
124      * <p>Set the encoding type for this form submit.</p>
125      *
126      * @param enctype The new enctype path
127      */
128     public void setEnctype(String enctype) {
129 
130         this.enctype = enctype;
131 
132     }
133 
134 
135     /***
136      * <p>Return the component family to which this component belongs.</p>
137      */
138     public String getFamily() {
139 
140         return "org.apache.struts.faces.Form";
141 
142     }
143 
144 
145     /***
146      * <p>Return the focus element name.</p>
147      */
148     public String getFocus() {
149 
150         if (this.focus != null) {
151             return (this.focus);
152         }
153         ValueBinding vb = getValueBinding("focus");
154         if (vb != null) {
155             return ((String) vb.getValue(getFacesContext()));
156         } else {
157             return (null);
158         }
159 
160     }
161 
162 
163     /***
164      * <p>Set the focus element name.</p>
165      *
166      * @param focus The new focus path
167      */
168     public void setFocus(String focus) {
169 
170         this.focus = focus;
171 
172     }
173 
174 
175     /***
176      * <p>Return the focus element index.</p>
177      */
178     public String getFocusIndex() {
179 
180         if (this.focusIndex != null) {
181             return (this.focusIndex);
182         }
183         ValueBinding vb = getValueBinding("focusIndex");
184         if (vb != null) {
185             return ((String) vb.getValue(getFacesContext()));
186         } else {
187             return (null);
188         }
189 
190     }
191 
192 
193     /***
194      * <p>Set the focus element index.</p>
195      *
196      * @param focusIndex The new focusIndex path
197      */
198     public void setFocusIndex(String focusIndex) {
199 
200         this.focusIndex = focusIndex;
201 
202     }
203 
204 
205     /***
206      * <p>Return the JavaScript to execute on form reset.</p>
207      */
208     public String getOnreset() {
209 
210         if (this.onreset != null) {
211             return (this.onreset);
212         }
213         ValueBinding vb = getValueBinding("onreset");
214         if (vb != null) {
215             return ((String) vb.getValue(getFacesContext()));
216         } else {
217             return (null);
218         }
219 
220     }
221 
222 
223     /***
224      * <p>Set the JavaScript to execute on form reset.</p>
225      *
226      * @param onreset The new onreset path
227      */
228     public void setOnreset(String onreset) {
229 
230         this.onreset = onreset;
231 
232     }
233 
234 
235     /***
236      * <p>Return the JavaScript to execute on form submit.</p>
237      */
238     public String getOnsubmit() {
239 
240         if (this.onsubmit != null) {
241             return (this.onsubmit);
242         }
243         ValueBinding vb = getValueBinding("onsubmit");
244         if (vb != null) {
245             return ((String) vb.getValue(getFacesContext()));
246         } else {
247             return (null);
248         }
249 
250     }
251 
252 
253     /***
254      * <p>Set the JavaScript to execute on form submit.</p>
255      *
256      * @param onsubmit The new onsubmit path
257      */
258     public void setOnsubmit(String onsubmit) {
259 
260         this.onsubmit = onsubmit;
261 
262     }
263 
264 
265     /***
266      * <p>Return the CSS style(s) to be rendered for this component.</p>
267      */
268     public String getStyle() {
269 
270         ValueBinding vb = getValueBinding("style");
271         if (vb != null) {
272             return (String) vb.getValue(getFacesContext());
273         } else {
274             return style;
275         }
276 
277     }
278 
279 
280     /***
281      * <p>Set the CSS style(s) to be rendered for this component.</p>
282      *
283      * @param style The new CSS style(s)
284      */
285     public void setStyle(String style) {
286 
287         this.style = style;
288 
289     }
290 
291 
292     /***
293      * <p>Return the CSS style class(es) to be rendered for this component.</p>
294      */
295     public String getStyleClass() {
296 
297         ValueBinding vb = getValueBinding("styleClass");
298         if (vb != null) {
299             return (String) vb.getValue(getFacesContext());
300         } else {
301             return styleClass;
302         }
303 
304     }
305 
306 
307     /***
308      * <p>Set the CSS style class(es) to be rendered for this component.</p>
309      *
310      * @param styleClass The new CSS style class(es)
311      */
312     public void setStyleClass(String styleClass) {
313 
314         this.styleClass = styleClass;
315 
316     }
317 
318 
319     /***
320      * <p>Return the target frame for the response to this form submit.</p>
321      */
322     public String getTarget() {
323 
324         ValueBinding vb = getValueBinding("target");
325         if (vb != null) {
326             return (String) vb.getValue(getFacesContext());
327         } else {
328             return target;
329         }
330 
331     }
332 
333 
334     /***
335      * <p>Set the target frame for the response to this form submit.</p>
336      *
337      * @param target The new CSS target(s)
338      */
339     public void setTarget(String target) {
340 
341         this.target = target;
342 
343     }
344 
345 
346     // ---------------------------------------------------------- UIForm Methods
347 
348 
349     /***
350      * <p>Create an instance of the form bean (if necessary) before
351      * delegating to the standard decoding process.</p>
352      *
353      * @param context FacesContext for the request we are processing
354      */
355     public void processDecodes(FacesContext context) {
356 
357         if (context == null) {
358             throw new NullPointerException();
359         }
360 
361         if (log.isDebugEnabled()) {
362             log.debug("processDecodes(" + getClientId(context) + ")");
363         }
364 
365         // Create the form bean (if necessary)
366         Map params = context.getExternalContext().getRequestParameterMap();
367         if (params.containsKey(getClientId(context))) {
368             createActionForm(context);
369         }
370 
371         // Perform the standard decode processing
372         super.processDecodes(context);
373 
374     }
375 
376 
377     /***
378      * <p>Restore our state from the specified object.</p>
379      *
380      * @param context <code>FacesContext</code> for the current request
381      * @param state Object containing our saved state
382      */
383     public void restoreState(FacesContext context, Object state) {
384 
385         Object values[] = (Object[]) state;
386         super.restoreState(context, values[0]);
387         action = (String) values[1];
388         enctype = (String) values[2];
389         focus = (String) values[3];
390         focusIndex = (String) values[4];
391         onreset = (String) values[5];
392         onsubmit = (String) values[6];
393         style = (String) values[7];
394         styleClass = (String) values[8];
395         target = (String) values[9];
396 
397     }
398 
399 
400     /***
401      * <p>Create and return an object representing our state to be saved.</p>
402      *
403      * @param context <code>FacesContext</code> for the current request
404      */
405     public Object saveState(FacesContext context) {
406 
407         Object values[] = new Object[10];
408         values[0] = super.saveState(context);
409         values[1] = action;
410         values[2] = enctype;
411         values[3] = focus;
412         values[4] = focusIndex;
413         values[5] = onreset;
414         values[6] = onsubmit;
415         values[7] = style;
416         values[8] = styleClass;
417         values[9] = target;
418         return (values);
419 
420     }
421 
422 
423 
424     // ---------------------------------------------------------- Public Methods
425 
426 
427     /***
428      * <p>Create an appropriate form bean in the appropriate scope, if one
429      * does not already exist.</p>
430      *
431      * @param context FacesContext for the current request
432      *
433      * @exception IllegalArgumentException if no ActionConfig for the
434      *  specified action attribute can be located
435      * @exception IllegalArgumentException if no FormBeanConfig for the
436      *  specified form bean can be located
437      * @exception IllegalArgumentException if no ModuleConfig can be
438      *  located for this application module
439      */
440     public void createActionForm(FacesContext context) {
441 
442         // Look up the application module configuration information we need
443         ModuleConfig moduleConfig = lookupModuleConfig(context);
444 
445         // Look up the ActionConfig we are processing
446         String action = getAction();
447         ActionConfig actionConfig = moduleConfig.findActionConfig(action);
448         if (actionConfig == null) {
449             throw new IllegalArgumentException("Cannot find action '" +
450                                                action + "' configuration");
451         }
452 
453         // Does this ActionConfig specify a form bean?
454         String name = actionConfig.getName();
455         if (name == null) {
456             return;
457         }
458 
459         // Look up the FormBeanConfig we are processing
460         FormBeanConfig fbConfig = moduleConfig.findFormBeanConfig(name);
461         if (fbConfig == null) {
462             throw new IllegalArgumentException("Cannot find form bean '" +
463                                                name + "' configuration");
464         }
465 
466         // Does a usable form bean attribute already exist?
467         String attribute = actionConfig.getAttribute();
468         String scope = actionConfig.getScope();
469         ActionForm instance = null;
470         if ("request".equals(scope)) {
471             instance = (ActionForm)
472                 context.getExternalContext().getRequestMap().get(attribute);
473         } else if ("session".equals(scope)) {
474             HttpSession session = (HttpSession)
475                 context.getExternalContext().getSession(true);
476             instance = (ActionForm)
477                 context.getExternalContext().getSessionMap().get(attribute);
478         }
479         if (instance != null) {
480             if (fbConfig.getDynamic()) {
481                 String className =
482                     ((DynaBean) instance).getDynaClass().getName();
483                 if (className.equals(fbConfig.getName())) {
484                     if (log.isDebugEnabled()) {
485                         log.debug
486                             (" Recycling existing DynaActionForm instance " +
487                              "of type '" + className + "'");
488                     }
489                     return;
490                 }
491             } else {
492                 try {
493                     Class configClass =
494                         RequestUtils.applicationClass(fbConfig.getType());
495                     if (configClass.isAssignableFrom(instance.getClass())) {
496                         if (log.isDebugEnabled()) {
497                             log.debug
498                                 (" Recycling existing ActionForm instance " +
499                                  "of class '" + instance.getClass().getName()
500                                  + "'");
501                         }
502                         return;
503                     }
504                 } catch (Throwable t) {
505                     throw new IllegalArgumentException
506                         ("Cannot load form bean class '" +
507                          fbConfig.getType() + "'");
508                 }
509             }
510         }
511 
512         // Create a new form bean instance
513         if (fbConfig.getDynamic()) {
514             try {
515                 DynaActionFormClass dynaClass =
516                     DynaActionFormClass.createDynaActionFormClass(fbConfig);
517                 instance = (ActionForm) dynaClass.newInstance();
518                 if (log.isDebugEnabled()) {
519                     log.debug
520                         (" Creating new DynaActionForm instance " +
521                          "of type '" + fbConfig.getType() + "'");
522                     log.trace(" --> " + instance);
523                 }
524             } catch (Throwable t) {
525                 throw new IllegalArgumentException
526                     ("Cannot create form bean of type '" +
527                      fbConfig.getType() + "'");
528             }
529         } else {
530             try {
531                 instance = (ActionForm)
532                     RequestUtils.applicationInstance(fbConfig.getType());
533                 if (log.isDebugEnabled()) {
534                     log.debug
535                         (" Creating new ActionForm instance " +
536                          "of type '" + fbConfig.getType() + "'");
537                     log.trace(" --> " + instance);
538                 }
539             } catch (Throwable t) {
540                 throw new IllegalArgumentException
541                     ("Cannot create form bean of class '" +
542                      fbConfig.getType() + "'");
543             }
544         }
545 
546         // Configure and cache the form bean instance in the correct scope
547         ActionServlet servlet = (ActionServlet)
548             context.getExternalContext().getApplicationMap().get
549             (Globals.ACTION_SERVLET_KEY);
550         instance.setServlet(servlet);
551         if ("request".equals(scope)) {
552             context.getExternalContext().getRequestMap().put
553                 (attribute, instance);
554         } else if ("session".equals(scope)) {
555             context.getExternalContext().getSessionMap().put
556                 (attribute, instance);
557         }
558 
559     }
560 
561 
562     /***
563      * <p>Return the <code>ModuleConfig</code> for the application module
564      * this form is being processed for.</p>
565      *
566      * @param context The <code>FacesContext</code> for the current request
567      *
568      * @exception IllegalArgumentException if no <code>ModuleConfig</code>
569      *  can be found
570      */
571     public ModuleConfig lookupModuleConfig(FacesContext context) {
572 
573         // Look up the application module configuration information we need
574         ModuleConfig modConfig = (ModuleConfig)
575             context.getExternalContext().getRequestMap().get
576             (Globals.MODULE_KEY);
577         if (modConfig == null) {
578             modConfig = (ModuleConfig)
579                 context.getExternalContext().getApplicationMap().get
580                 (Globals.MODULE_KEY);
581         }
582         if (modConfig == null) {
583             throw new IllegalArgumentException
584                 ("Cannot find module configuration");
585         }
586         return (modConfig);
587 
588     }
589 
590 
591 }