001: /*
002: * $Id: FormComponent.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: package org.apache.struts.faces.component;
023:
024: import java.util.Map;
025: import javax.faces.component.UIForm;
026: import javax.faces.context.FacesContext;
027: import javax.faces.el.ValueBinding;
028: import javax.servlet.http.HttpSession;
029: import org.apache.commons.beanutils.DynaBean;
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.apache.struts.Globals;
033: import org.apache.struts.action.ActionForm;
034: import org.apache.struts.action.ActionServlet;
035: import org.apache.struts.action.DynaActionFormClass;
036: import org.apache.struts.config.ActionConfig;
037: import org.apache.struts.config.FormBeanConfig;
038: import org.apache.struts.config.ModuleConfig;
039: import org.apache.struts.util.RequestUtils;
040:
041: /**
042: * <p><strong>FormComponent</strong> is a specialized subclass of
043: * <code>javax.faces.component.UIForm</code> that supports automatic
044: * creation of form beans in request or session scope.</p>
045: *
046: * @version $Rev: 471754 $ $Date: 2006-11-06 08:55:09 -0600 (Mon, 06 Nov 2006) $
047: */
048: public class FormComponent extends UIForm {
049:
050: // -------------------------------------------------------- Static Variables
051:
052: /**
053: * <p>The <code>Log</code> instance for this class.</p>
054: */
055: protected static Log log = LogFactory.getLog(FormComponent.class);
056:
057: // ------------------------------------------------------ Instance Variables
058:
059: private String action = null;
060: private String enctype = null;
061: private String focus = null;
062: private String focusIndex = null;
063: private String onreset = null;
064: private String onsubmit = null;
065: private String style = null;
066: private String styleClass = null;
067: private String target = null;
068:
069: // ---------------------------------------------------- Component Properties
070:
071: /**
072: * <p>Return the Struts action path to which this form should be submitted.
073: * </p>
074: */
075: public String getAction() {
076:
077: if (this .action != null) {
078: return (this .action);
079: }
080: ValueBinding vb = getValueBinding("action");
081: if (vb != null) {
082: return ((String) vb.getValue(getFacesContext()));
083: } else {
084: return (null);
085: }
086:
087: }
088:
089: /**
090: * <p>Set the Struts action to which this form should be submitted.</p>
091: *
092: * @param action The new action path
093: */
094: public void setAction(String action) {
095:
096: this .action = action;
097:
098: }
099:
100: /**
101: * <p>Return the encoding type for this form submit.</p>
102: */
103: public String getEnctype() {
104:
105: if (this .enctype != null) {
106: return (this .enctype);
107: }
108: ValueBinding vb = getValueBinding("enctype");
109: if (vb != null) {
110: return ((String) vb.getValue(getFacesContext()));
111: } else {
112: return (null);
113: }
114:
115: }
116:
117: /**
118: * <p>Set the encoding type for this form submit.</p>
119: *
120: * @param enctype The new enctype path
121: */
122: public void setEnctype(String enctype) {
123:
124: this .enctype = enctype;
125:
126: }
127:
128: /**
129: * <p>Return the component family to which this component belongs.</p>
130: */
131: public String getFamily() {
132:
133: return "org.apache.struts.faces.Form";
134:
135: }
136:
137: /**
138: * <p>Return the focus element name.</p>
139: */
140: public String getFocus() {
141:
142: if (this .focus != null) {
143: return (this .focus);
144: }
145: ValueBinding vb = getValueBinding("focus");
146: if (vb != null) {
147: return ((String) vb.getValue(getFacesContext()));
148: } else {
149: return (null);
150: }
151:
152: }
153:
154: /**
155: * <p>Set the focus element name.</p>
156: *
157: * @param focus The new focus path
158: */
159: public void setFocus(String focus) {
160:
161: this .focus = focus;
162:
163: }
164:
165: /**
166: * <p>Return the focus element index.</p>
167: */
168: public String getFocusIndex() {
169:
170: if (this .focusIndex != null) {
171: return (this .focusIndex);
172: }
173: ValueBinding vb = getValueBinding("focusIndex");
174: if (vb != null) {
175: return ((String) vb.getValue(getFacesContext()));
176: } else {
177: return (null);
178: }
179:
180: }
181:
182: /**
183: * <p>Set the focus element index.</p>
184: *
185: * @param focusIndex The new focusIndex path
186: */
187: public void setFocusIndex(String focusIndex) {
188:
189: this .focusIndex = focusIndex;
190:
191: }
192:
193: /**
194: * <p>Return the JavaScript to execute on form reset.</p>
195: */
196: public String getOnreset() {
197:
198: if (this .onreset != null) {
199: return (this .onreset);
200: }
201: ValueBinding vb = getValueBinding("onreset");
202: if (vb != null) {
203: return ((String) vb.getValue(getFacesContext()));
204: } else {
205: return (null);
206: }
207:
208: }
209:
210: /**
211: * <p>Set the JavaScript to execute on form reset.</p>
212: *
213: * @param onreset The new onreset path
214: */
215: public void setOnreset(String onreset) {
216:
217: this .onreset = onreset;
218:
219: }
220:
221: /**
222: * <p>Return the JavaScript to execute on form submit.</p>
223: */
224: public String getOnsubmit() {
225:
226: if (this .onsubmit != null) {
227: return (this .onsubmit);
228: }
229: ValueBinding vb = getValueBinding("onsubmit");
230: if (vb != null) {
231: return ((String) vb.getValue(getFacesContext()));
232: } else {
233: return (null);
234: }
235:
236: }
237:
238: /**
239: * <p>Set the JavaScript to execute on form submit.</p>
240: *
241: * @param onsubmit The new onsubmit path
242: */
243: public void setOnsubmit(String onsubmit) {
244:
245: this .onsubmit = onsubmit;
246:
247: }
248:
249: /**
250: * <p>Return the CSS style(s) to be rendered for this component.</p>
251: */
252: public String getStyle() {
253:
254: ValueBinding vb = getValueBinding("style");
255: if (vb != null) {
256: return (String) vb.getValue(getFacesContext());
257: } else {
258: return style;
259: }
260:
261: }
262:
263: /**
264: * <p>Set the CSS style(s) to be rendered for this component.</p>
265: *
266: * @param style The new CSS style(s)
267: */
268: public void setStyle(String style) {
269:
270: this .style = style;
271:
272: }
273:
274: /**
275: * <p>Return the CSS style class(es) to be rendered for this component.</p>
276: */
277: public String getStyleClass() {
278:
279: ValueBinding vb = getValueBinding("styleClass");
280: if (vb != null) {
281: return (String) vb.getValue(getFacesContext());
282: } else {
283: return styleClass;
284: }
285:
286: }
287:
288: /**
289: * <p>Set the CSS style class(es) to be rendered for this component.</p>
290: *
291: * @param styleClass The new CSS style class(es)
292: */
293: public void setStyleClass(String styleClass) {
294:
295: this .styleClass = styleClass;
296:
297: }
298:
299: /**
300: * <p>Return the target frame for the response to this form submit.</p>
301: */
302: public String getTarget() {
303:
304: ValueBinding vb = getValueBinding("target");
305: if (vb != null) {
306: return (String) vb.getValue(getFacesContext());
307: } else {
308: return target;
309: }
310:
311: }
312:
313: /**
314: * <p>Set the target frame for the response to this form submit.</p>
315: *
316: * @param target The new CSS target(s)
317: */
318: public void setTarget(String target) {
319:
320: this .target = target;
321:
322: }
323:
324: // ---------------------------------------------------------- UIForm Methods
325:
326: /**
327: * <p>Create an instance of the form bean (if necessary) before
328: * delegating to the standard decoding process.</p>
329: *
330: * @param context FacesContext for the request we are processing
331: */
332: public void processDecodes(FacesContext context) {
333:
334: if (context == null) {
335: throw new NullPointerException();
336: }
337:
338: if (log.isDebugEnabled()) {
339: log.debug("processDecodes(" + getClientId(context) + ")");
340: }
341:
342: // Create the form bean (if necessary)
343: Map params = context.getExternalContext()
344: .getRequestParameterMap();
345: if (params.containsKey(getClientId(context))) {
346: createActionForm(context);
347: }
348:
349: // Perform the standard decode processing
350: super .processDecodes(context);
351:
352: }
353:
354: /**
355: * <p>Restore our state from the specified object.</p>
356: *
357: * @param context <code>FacesContext</code> for the current request
358: * @param state Object containing our saved state
359: */
360: public void restoreState(FacesContext context, Object state) {
361:
362: Object values[] = (Object[]) state;
363: super .restoreState(context, values[0]);
364: action = (String) values[1];
365: enctype = (String) values[2];
366: focus = (String) values[3];
367: focusIndex = (String) values[4];
368: onreset = (String) values[5];
369: onsubmit = (String) values[6];
370: style = (String) values[7];
371: styleClass = (String) values[8];
372: target = (String) values[9];
373:
374: }
375:
376: /**
377: * <p>Create and return an object representing our state to be saved.</p>
378: *
379: * @param context <code>FacesContext</code> for the current request
380: */
381: public Object saveState(FacesContext context) {
382:
383: Object values[] = new Object[10];
384: values[0] = super .saveState(context);
385: values[1] = action;
386: values[2] = enctype;
387: values[3] = focus;
388: values[4] = focusIndex;
389: values[5] = onreset;
390: values[6] = onsubmit;
391: values[7] = style;
392: values[8] = styleClass;
393: values[9] = target;
394: return (values);
395:
396: }
397:
398: // ---------------------------------------------------------- Public Methods
399:
400: /**
401: * <p>Create an appropriate form bean in the appropriate scope, if one
402: * does not already exist.</p>
403: *
404: * @param context FacesContext for the current request
405: *
406: * @exception IllegalArgumentException if no ActionConfig for the
407: * specified action attribute can be located
408: * @exception IllegalArgumentException if no FormBeanConfig for the
409: * specified form bean can be located
410: * @exception IllegalArgumentException if no ModuleConfig can be
411: * located for this application module
412: */
413: public void createActionForm(FacesContext context) {
414:
415: // Look up the application module configuration information we need
416: ModuleConfig moduleConfig = lookupModuleConfig(context);
417:
418: // Look up the ActionConfig we are processing
419: String action = getAction();
420: ActionConfig actionConfig = moduleConfig
421: .findActionConfig(action);
422: if (actionConfig == null) {
423: throw new IllegalArgumentException("Cannot find action '"
424: + action + "' configuration");
425: }
426:
427: // Does this ActionConfig specify a form bean?
428: String name = actionConfig.getName();
429: if (name == null) {
430: return;
431: }
432:
433: // Look up the FormBeanConfig we are processing
434: FormBeanConfig fbConfig = moduleConfig.findFormBeanConfig(name);
435: if (fbConfig == null) {
436: throw new IllegalArgumentException(
437: "Cannot find form bean '" + name
438: + "' configuration");
439: }
440:
441: // Does a usable form bean attribute already exist?
442: String attribute = actionConfig.getAttribute();
443: String scope = actionConfig.getScope();
444: ActionForm instance = null;
445: if ("request".equals(scope)) {
446: instance = (ActionForm) context.getExternalContext()
447: .getRequestMap().get(attribute);
448: } else if ("session".equals(scope)) {
449: HttpSession session = (HttpSession) context
450: .getExternalContext().getSession(true);
451: instance = (ActionForm) context.getExternalContext()
452: .getSessionMap().get(attribute);
453: }
454: if (instance != null) {
455: if (fbConfig.getDynamic()) {
456: String className = ((DynaBean) instance).getDynaClass()
457: .getName();
458: if (className.equals(fbConfig.getName())) {
459: if (log.isDebugEnabled()) {
460: log
461: .debug(" Recycling existing DynaActionForm instance "
462: + "of type '" + className + "'");
463: }
464: return;
465: }
466: } else {
467: try {
468: Class configClass = RequestUtils
469: .applicationClass(fbConfig.getType());
470: if (configClass.isAssignableFrom(instance
471: .getClass())) {
472: if (log.isDebugEnabled()) {
473: log
474: .debug(" Recycling existing ActionForm instance "
475: + "of class '"
476: + instance.getClass()
477: .getName() + "'");
478: }
479: return;
480: }
481: } catch (Throwable t) {
482: throw new IllegalArgumentException(
483: "Cannot load form bean class '"
484: + fbConfig.getType() + "'");
485: }
486: }
487: }
488:
489: // Create a new form bean instance
490: if (fbConfig.getDynamic()) {
491: try {
492: DynaActionFormClass dynaClass = DynaActionFormClass
493: .createDynaActionFormClass(fbConfig);
494: instance = (ActionForm) dynaClass.newInstance();
495: if (log.isDebugEnabled()) {
496: log.debug(" Creating new DynaActionForm instance "
497: + "of type '" + fbConfig.getType() + "'");
498: log.trace(" --> " + instance);
499: }
500: } catch (Throwable t) {
501: throw new IllegalArgumentException(
502: "Cannot create form bean of type '"
503: + fbConfig.getType() + "'");
504: }
505: } else {
506: try {
507: instance = (ActionForm) RequestUtils
508: .applicationInstance(fbConfig.getType());
509: if (log.isDebugEnabled()) {
510: log.debug(" Creating new ActionForm instance "
511: + "of type '" + fbConfig.getType() + "'");
512: log.trace(" --> " + instance);
513: }
514: } catch (Throwable t) {
515: throw new IllegalArgumentException(
516: "Cannot create form bean of class '"
517: + fbConfig.getType() + "'");
518: }
519: }
520:
521: // Configure and cache the form bean instance in the correct scope
522: ActionServlet servlet = (ActionServlet) context
523: .getExternalContext().getApplicationMap().get(
524: Globals.ACTION_SERVLET_KEY);
525: instance.setServlet(servlet);
526: if ("request".equals(scope)) {
527: context.getExternalContext().getRequestMap().put(attribute,
528: instance);
529: } else if ("session".equals(scope)) {
530: context.getExternalContext().getSessionMap().put(attribute,
531: instance);
532: }
533:
534: }
535:
536: /**
537: * <p>Return the <code>ModuleConfig</code> for the application module
538: * this form is being processed for.</p>
539: *
540: * @param context The <code>FacesContext</code> for the current request
541: *
542: * @exception IllegalArgumentException if no <code>ModuleConfig</code>
543: * can be found
544: */
545: public ModuleConfig lookupModuleConfig(FacesContext context) {
546:
547: // Look up the application module configuration information we need
548: ModuleConfig modConfig = (ModuleConfig) context
549: .getExternalContext().getRequestMap().get(
550: Globals.MODULE_KEY);
551: if (modConfig == null) {
552: modConfig = (ModuleConfig) context.getExternalContext()
553: .getApplicationMap().get(Globals.MODULE_KEY);
554: }
555: if (modConfig == null) {
556: throw new IllegalArgumentException(
557: "Cannot find module configuration");
558: }
559: return (modConfig);
560:
561: }
562:
563: }
|