craigmcc 01/01/27 15:21:09 Modified: src/doc struts-html.xml src/share/org/apache/struts/taglib/html FormTag.java LocalStrings.properties Log: Improve the mechanism by which the <html:form> tag calculates the action mapping to which this form will be submitted. Now, it should work for all of the following cases: * Extension mapped: "logon.do" or "/logon.do" or "/admin/logon.do" * Path mapped: "/execute/logon" In all cases, a server-relative URL will be generated by prepending the context path. This patch is based on the patch submitted by Chris Smith <[EMAIL PROTECTED]>, but modified to work for path mapped servlets as well. Revision Changes Path 1.4 +54 -24 jakarta-struts/src/doc/struts-html.xml Index: struts-html.xml =================================================================== RCS file: /home/cvs/jakarta-struts/src/doc/struts-html.xml,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- struts-html.xml 2001/01/27 20:09:42 1.3 +++ struts-html.xml 2001/01/27 23:21:07 1.4 @@ -985,15 +985,25 @@ <attribute> <name>action</name> - <required>false</required> + <required>true</required> <rtexprvalue>true</rtexprvalue> <info> - The URL to which this form will be submitted. Typically, this will - match a mapping for the ActionServlet managing this application. - URL rewriting will automatically be performed on this URL, to - maintain session state in the absence of cookies. [Form will be - submitted to this page itself] - </info> + <p>The URL to which this form will be submitted. This + value is also used to select the ActionMapping we are + assumed to be processing, from which we can identify + the appropriate form bean and scope.</p> + + <p>If you are using extension mapping for selecting the + controller servlet, this value should be equal to the + <code>path</code> attribute of the corresponding + <code><action></code> element, plus the correct + file extension suffix.</p> + + <p>If you are using path mapping to select the + controller servlet, this value should be exactly equal + to the <code>path</code> attribute of the corresponding + <code><action></code> element.</p> + </info> </attribute> <attribute> @@ -1034,14 +1044,22 @@ <required>false</required> <rtexprvalue>true</rtexprvalue> <info> - Name of the request scope or session scope bean (as defined by - the scope attribute) whose properties will be used to populate - input field values. If no such bean is found, a new bean will - be created (and added to the appropriate scope), using the Java - class name specified by the type attribute. - </info> - </attribute> - + <p>Name of the request scope or session scope bean + (as defined by the <code>scope</code> attribute) + whose properties will be used to populate the input + field values. If no such bean is found, a new bean + will be created and added to the appropriate scope, + using the Java class name specified by the + <code>type</code> attribute.</p> + + <p>If this attribute is not specified, it will be + calculated by using the value of the + <code>action</code> attribute to look up the + corresponding ActionMapping element, from which + we will select the specified form bean name.</p> + </info> + </attribute> + <attribute> <name>onreset</name> <required>false</required> @@ -1065,9 +1083,17 @@ <required>false</required> <rtexprvalue>true</rtexprvalue> <info> - JSP scope within which the associated bean will be accessed - or created (request, session). [session] - </info> + <p>Scope within which the form bean associated with + this input form will be accessed or created (must be + either <code>request</code> or <code>session</code>. + </p> + + <p>If this attribute is not specified, it will be + calculated by using the value of the + <code>action</code> attribute to look up the + corresponding ActionMapping element, from which + we will select the specified form bean scope.</p> + </info> </attribute> <attribute> @@ -1103,12 +1129,16 @@ <required>false</required> <rtexprvalue>true</rtexprvalue> <info> - Fully qualified Java class name of the bean to be created - if no bean is found for the specified name and scope. To - be used successfully with the Struts ActionServlet, this class - must implement the org.apache.struts.action.ActionForm interface. - [Runtime error if bean creation is attempted] - </info> + <p>Fully qualified Java class name of the form bean to + be created, if no such bean is found in the specified + scope.</p> + + <p>If this attribute is not specified, it will be + calculated by using the value of the + <code>action</code> attribute to look up the + corresponding ActionMapping element, from which + we will select the specified form bean type.</p> + </info> </attribute> </tag> 1.4 +130 -68 jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java Index: FormTag.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- FormTag.java 2001/01/26 19:27:23 1.3 +++ FormTag.java 2001/01/27 23:21:08 1.4 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java,v 1.3 2001/01/26 19:27:23 craigmcc Exp $ - * $Revision: 1.3 $ - * $Date: 2001/01/26 19:27:23 $ + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java,v 1.4 2001/01/27 23:21:08 craigmcc Exp $ + * $Revision: 1.4 $ + * $Date: 2001/01/27 23:21:08 $ * * ==================================================================== * @@ -64,12 +64,12 @@ import java.io.IOException; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; -import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.tagext.TagSupport; import org.apache.struts.action.Action; import org.apache.struts.action.ActionFormBean; @@ -85,7 +85,7 @@ * properties correspond to the various fields of the form. * * @author Craig R. McClanahan - * @version $Revision: 1.3 $ $Date: 2001/01/26 19:27:23 $ + * @version $Revision: 1.4 $ $Date: 2001/01/27 23:21:08 $ */ public class FormTag extends TagSupport { @@ -184,28 +184,7 @@ // ------------------------------------------------------------- Properties - /** - * Returns a form action converted into an action mapping path. - * Anything after a period (".") is considered a name extension and ignored. - * Anything before the last forward slash ("/") is considered a name - * extension and ignored. - */ - protected String getActionMappingName() { - String retString = action; - int period = action.lastIndexOf("."); - int slash = action.lastIndexOf("/"); - if (period < slash) - period = -1; - if (period > -1) { - retString = action.substring(0, period); - } - if (slash > -1) { - retString = retString.substring(slash+1, retString.length()); - } - return "/" + retString; - } - - + /** * Return the action URL to which this form should be submitted. */ @@ -458,41 +437,8 @@ */ public int doStartTag() throws JspException { - //get unspecified values - if ((name == null) || (type == null)) { - //get ActionMapping specified by "action" - ActionMappings mappings = (ActionMappings) - pageContext.getAttribute(Action.MAPPINGS_KEY, - PageContext.APPLICATION_SCOPE); - ActionFormBeans formBeans = (ActionFormBeans) - pageContext.getAttribute(Action.FORM_BEANS_KEY, - PageContext.APPLICATION_SCOPE); - if ((mappings != null) && (formBeans != null)) { - String actionMappingName = getActionMappingName(); - ActionMapping mapping = mappings.findMapping(actionMappingName); - - if (mapping != null) { - this.scope = mapping.getScope(); - if (name == null) { - this.name = mapping.getAttribute(); - } - if (type == null) { - ActionFormBean formBean = - formBeans.findFormBean(mapping.getName()); - if (formBean != null) - this.type = formBean.getType(); - } - } - else { - throw new JspTagException("Cannot retrieve mapping for specified form " + - "action path \"" + actionMappingName + "\""); - } - } - else { - throw new JspTagException("Cannot retrieve ActionMappings under key \"" + - Action.MAPPINGS_KEY + "\""); - } - } + // Look up the form bean name, scope, and type if necessary + lookup(); // Create an appropriate "form" element based on our parameters HttpServletResponse response = @@ -503,12 +449,10 @@ results.append("\""); results.append(" method=\""); results.append(method); - results.append("\""); - if (action != null) { - results.append(" action=\""); - results.append(response.encodeURL(BeanUtils.filter(action))); - results.append("\""); - } + results.append("\" action=\""); + results.append + (response.encodeURL(BeanUtils.filter(getActionMappingURL()))); + results.append("\""); if (styleClass != null) { results.append(" class=\""); results.append(styleClass); @@ -654,6 +598,124 @@ styleClass = null; target = null; type = null; + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return the form action converted into an action mapping path. The + * value of the <code>action</code> property is manipulated as follows in + * computing the name of the requested mapping: + * <ul> + * <li>Any filename extension is removed (on the theory that extension + * mapping is being used to select the controller servlet).</li> + * <li>If the resulting value does not start with a slash, then a + * slash is prepended.</li> + * </ul> + */ + protected String getActionMappingName() { + + String value = action; + int slash = action.lastIndexOf("/"); + int period = action.lastIndexOf("."); + if ((period >= 0) && (period > slash)) + value = value.substring(0, period); + if (value.startsWith("/")) + return (value); + else + return ("/" + value); + + } + + + /** + * Return the form action converted into a server-relative URL. The + * URL string is composed of the following pieces: + * <ul> + * <li>The context path of this web application.</li> + * <li>If the <code>action</code> property value does not start with + * a slash, a slash is inserted.</li> + * <li>The <code>action</code> property value.</li> + */ + protected String getActionMappingURL() { + + HttpServletRequest request = + (HttpServletRequest) pageContext.getRequest(); + StringBuffer value = new StringBuffer(request.getContextPath()); + if (!action.startsWith("/")) + value.append("/"); + value.append(action); + return (value.toString()); + + } + + + /** + * Look up values for the <code>name</code>, <code>scope</code>, and + * <code>type</code> properties if necessary. + * + * @exception JspException if a required value cannot be looked up + */ + protected void lookup() throws JspException { + + // Were the required values already specified? + if (name != null) { + if (scope == null) + scope = "session"; + if (type == null) { + JspException e = new JspException + (messages.getMessage("formTag.nameType")); + pageContext.setAttribute(Action.EXCEPTION_KEY, e, + PageContext.REQUEST_SCOPE); + throw e; + } + return; + } + + // Look up the application scope collections that we need + ActionMappings mappings = (ActionMappings) + pageContext.getAttribute(Action.MAPPINGS_KEY, + PageContext.APPLICATION_SCOPE); + ActionFormBeans formBeans = (ActionFormBeans) + pageContext.getAttribute(Action.FORM_BEANS_KEY, + PageContext.APPLICATION_SCOPE); + if ((mappings == null) || (formBeans == null)) { + JspException e = new JspException + (messages.getMessage("formTag.collections")); + pageContext.setAttribute(Action.EXCEPTION_KEY, e, + PageContext.REQUEST_SCOPE); + throw e; + } + + // Look up the action mapping we will be submitting to + String mappingName = getActionMappingName(); + ActionMapping mapping = mappings.findMapping(mappingName); + if (mapping == null) { + JspException e = new JspException + (messages.getMessage("formTag.mapping", mappingName)); + pageContext.setAttribute(Action.EXCEPTION_KEY, e, + PageContext.REQUEST_SCOPE); + throw e; + } + + // Look up the form bean definition + ActionFormBean formBean = + formBeans.findFormBean(mapping.getName()); + if (formBean == null) { + JspException e = new JspException + (messages.getMessage("formTag.formBean", mapping.getName())); + pageContext.setAttribute(Action.EXCEPTION_KEY, e, + PageContext.REQUEST_SCOPE); + throw e; + } + + // Calculate the required values + name = mapping.getName(); + scope = mapping.getScope(); + type = formBean.getType(); } 1.2 +4 -0 jakarta-struts/src/share/org/apache/struts/taglib/html/LocalStrings.properties Index: LocalStrings.properties =================================================================== RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/LocalStrings.properties,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- LocalStrings.properties 2001/01/06 21:50:39 1.1 +++ LocalStrings.properties 2001/01/27 23:21:08 1.2 @@ -1,6 +1,10 @@ common.io=Encountered input/output error: {0} enumerateTag.enumeration=Cannot create enumeration for {0} +formTag.collections=Cannot find ActionMappings or ActionFormBeans collection formTag.create=Exception creating bean of class {0}: {1} +formTag.formBean=Cannot retrieve definition for form bean {0} +formTag.mapping=Cannot retrieve mapping for action {0} +formTag.nameType=Must specify type attribute if name is specified forwardTag.forward=Error forwarding to page {0}: {1} forwardTag.lookup=Cannot find global forward named {0} forwardTag.redirect=Error redirecting to path {0}: {1}