From: <jm...@us...> - 2005-07-11 07:13:19
|
Update of /cvsroot/struts/dialogs/src/net/jspcontrols/dialogs/actions In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12963/src/net/jspcontrols/dialogs/actions Added Files: DialogAction.java DialogConstants.java SelectAction.java package.html Log Message: --- NEW FILE: DialogAction.java --- /* * Copyright 2004-2005 Michael Jouravlev. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jspcontrols.dialogs.actions; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMessages; import org.apache.struts.Globals; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.Enumeration; /** * <p>An abstract <strong>Action</strong> that provides basic dialog functions, * like accepting input data, dispatching submit event to a method, generating * and storing error messages and rendering a view. DialogAction allows to * create robust user inteface and provides simple event-based programming accounts.</p> * * <p>DialogAction incorporates several innovative design decisions not previously * used in Struts. Some of them are already implemented in other frameworks, * like Ruby on Rails or JSF. Other features are unique to DialogAction.</p> * * <p><strong>Input/Output Separation</strong></p> * * <p>The cornerstone concept of DialogAction is <i>separation of input and output * processes</i>. It solves several issues, related to HTML form input, * like double submit problem, annoying POSTDATA messages, bad usability * when Reload, Back and Forward buttons are used.</p> * * <p>DialogAction defines three different modes of operation:</p> * <ul> * <li><i>action initialization</i> prepares action for use with new set of data; * <li><i>user input process</i> accepts input data, updates domain accounts, * generates error messages; * <li><i>view rendering process</i> generates a result page. * </ul> * * <p>HTTP specification recommends to use POST request method for server state * modification, and GET method for requests with no side effects. Therefore, * input and output processes in DialogAction are cleanly separated * by request method:</p> * <ul> * <li>Browser sends input data to <nop>DialogAction using POST request. * <li>Web application redirects browser to the location of result page. * <li>Browser loads result page using GET request. * Because this pattern includes redirection, it can also be called as * "Redirect-After-Post" or "Post/Redirect/Get". * </ul> * * <img border="0" align="center" src="doc-files/inputaction.gif" width="500" height="540"> * * <p>It must be understood, that redirection is an inherent part of this pattern. * Redirection allows to split one solid "POST input data, respond * with result page" process into two processes, which are completely * independent from server standpoint.</p> * * <p>Separation of input and output improves usability and user experience:</p> * <ul> * <li>Any page can be reloaded without resending input information to the server. * <li>As a consequence, an application does not have to cope with double submits. * <li>Another consequence is that a user does not see "Do you want to resend * POSTDATA?" message. * <li>Using Back and Forward buttons is safe, because only result pages * are browsed. * <li>If an action has several views corresponding to different application * states, every view is displayed in response to exactly the same * GET request. From browser's point of view the action always returns * the same page. This simple trick allows creating <i>web controls</i>. * Even better, some popular browsers like Internet Explorer or * Mozilla/Firefox do not add every result page to browser session history * if pages originate from the same location. * </ul> * * <p><strong>Event Handlers and View Renderer</strong></p> * * <p>Event handlers have the same signature, as execute method, and * process POST events, usually from submit buttons of HTML form. * An initialization event is one exception from this rule, and can be * processed as either POST or GET request. Initialization event has * a default key, DIALOG-EVENT-INIT.</p> * * <p>After input event is processed, DialogAction redirects to itself and * receives GET request from a browser. The same GET request is sent by * the browser when a user reloads a page. In both cases, GET request * is processed by <code>getView</code> method, which renders an output page.</p> * * <p>"Rendering" is probably a too strong word to what <code>getView</code> * method actually does. It simply chooses a mapping name of a JSP page * corresponding to current dialog state, and returns this mapping to Struts * in the same fashion as a regular action.</p> * * <p>If a dialog action has only one page to render, then default * <code>getView</code> implementation, which returns DIALOG-EVENT-VIEW key, * is sufficient. The only thing you need to do is to define * a <code>forward</code> element in the struts-config.xml file, * which maps view key to a JSP page. * * <p>If a dialog action can render different pages depending on application * state, it is called a <i>web control</i>. In this case <code>getView</code> * method should be overriden, and a proper mapping should be returned.</p> * * <p><strong>Default keys and mappings</strong></p> * * <p>DialogAction uses several predefined keys and mappings, to correlate * HTML buttons to handler methods, and to select result pages. These mappings * are defined in DialogConstants class:</p> * * <p>String DIALOG-VIEW-KEY = "DIALOG-VIEW";<br> * This is a default view mapping, mandatory if a dialog action has only * one page to render. If dialog can render different pages depending * on application state, use action-specific mappings. * * <p>String DIALOG-RELOAD-KEY = "DIALOG-RELOAD";<br> * This is a default reload mapping, optional. Can be omitted if * a dialog action redirects to itself for view processing, which is * a default behavior. It is possible to split input and output * processing between two separate actions, in this case use this mapping * to set the "view action" name.</p> * * <p>String DIALOG-EVENT-KEY = "DIALOG-EVENT";<br> * This is a default prefix for dialog events.</p> * * <p>String DIALOG-EVENT-INIT = "DIALOG-EVENT-INIT";<br> * This is a default name of initialization parameter.</p> * * <p><strong>Usage</strong></p> * * <p>DialogAction is supposed to be used for HTML forms, which are submitted * using POST request method. When the form is submitted, DialogAction * dispatches submit event to a handler method. For this to happed, * automatic validation must be turned off. The hander should validate * input data explicitly, and perform accounts update.</p> * * <p>In case of error, the handler should save errors in the session * and redirect to the same action, this is called <i>action reloading</i>. * Would not this cause infinite loop? No, because request for data submission * has POST type, while redirected request for action reloading has GET type. * DialogAction processes requests differently, depending on their type. * Action reloading can be performed automatically, see the example.</p> * * <p>If no errors detected, control is usually handed over to another action. * Redirection is a preferred way to hand over the control to prevent double * submit issues.</p> * * <p>When a user refreshes a page, action treats the request in the same way * as for action reloading, and displays an appropriate view with current * form bean values. This implies that application state must be stored * on server with session or higher scope.</p> * * <p>A special initializing request parameter must be used to initialize * and reset <nop>DialogAction. This is necessary, because there is * no other way to distinguish linking to DialogAction from other page, * explicit refreshing of page corresponding to an action, or action reloading. * Action data will not be cleared by simply navigating to DialogAction, * instead current values will be shown.</p> * * <p><strong>Notes</strong></p> * <ul> * <li>DialogAction extends SelectAction, refer to SelectAction API * for description on how to define handler methods, and how * to name buttons on HTML page. * <li>Make sure that you turned "validate" property off in your * action mapping in struts-config.xml file. Errors must be processed * explicitly in the action class, but you can use any action form you like, * as well as standard <code>validate</code> method of action form. * <li>Make sure that your action form uses session scope to retain form * values between requests. If you are strongly against storing * application state on the server, this action class is not for you. * </ul> * * @see net.jspcontrols.dialogs.actions.SelectAction * @see net.jspcontrols.dialogs.actions.DialogConstants * @version 1.2 * * @author Michael Jouravlev */ public abstract class DialogAction extends SelectAction { /** * Returns the initialization key, or initialization key prefix if * several init keys are possible. Must start with the same prefix as * dialog buttons. */ protected String getInitKey() { return "DIALOG-EVENT-INIT"; } /** * Cleans messages stored in the session. Subclasses can override * this method if error messages are stored differently, or under * different key. * @param request the HTTP request we are processing */ protected void clearMessages(HttpServletRequest request) { HttpSession session = request.getSession(); if (session != null) { session.removeAttribute(Globals.ERROR_KEY); session.removeAttribute(Globals.MESSAGE_KEY); } } /** * Saves dialog errors in the session under Globals.ERROR_KEY key. * @param session HttpSession object * @param errors error messages, accumulated while processing input * @since 1.2 */ protected void saveDialogErrors(HttpSession session, ActionMessages errors) { session.setAttribute(Globals.ERROR_KEY, errors); } /** * Marks response as non-cachable. Should be called before page content * is written to response. * @param response The HTTP response we are creating * @since 1.2 */ protected void setNoCache(HttpServletResponse response) { response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); response.setDateHeader("Expires", 1); } /** * Returns suffix, used for action mapping. Default suffix is ".do" * Needed to properly setup location for dialog reloading. */ protected String getActionSuffix() { return ".do"; } /** * Returns true if request is considered "input" request. By convention * dialog input is sent via POST, result page is loaded via GET. * @param request The HTTP request we are processing */ protected boolean isInput(HttpServletRequest request) { return "POST".equalsIgnoreCase(request.getMethod()); } /** * Returns true if request is considered "init" request. DialogAction * uses a special request parameter to initialize action, because it * is impossible to distinguish a page refresh from navigating to an * action via a link, both use GET request method. * <p> * Initialization parameter must be defined in a concrete subclass. * @param request The HTTP request we are processing */ protected boolean isInit(HttpServletRequest request) { String initKey = getInitKey(); // Flag that dialog is initialized with explicit init parameter, // either with POST or with GET request. boolean isInit = false; // Find request parameter, starting with initKey Enumeration reqEn = request.getParameterNames(); while(reqEn.hasMoreElements()) { String reqName = (String) reqEn.nextElement(); if (reqName.startsWith(initKey)) { isInit = true; break; } } return isInit; } /** * Returns true, if GET request contains session ID both in cookie and * in the URL itself. This combination identifies the first request after * session has been established, with browser which supports cookies. * <p> * DialogAction tries to keep GET requests clean to encourage browser * to keep its page history from growing. When DialogAction detects * bogus request, it redirects to itself to ensure clean URL. This time * it will be clean, because session ID will be contained in cookie only. * @param request The HTTP request we are processing */ protected boolean isBogusGET(HttpServletRequest request) { // Note: on Tomcat 4-1-31 when session ID is present in both URL // an in cookie, isRequestedSessionIdFromURL() returns false, // while isRequestedSessionIdFromCookie() returns true. // Is it a bug or is required by spec? return request.isRequestedSessionIdFromURL() && request.isRequestedSessionIdFromCookie(); } /** * Returns the method name, given a prefix and a request object. * This is a helper method, which should not normally be redefined * by a subclass. * * @param mapping The ActionMapping used to select this instance * @param form The optional ActionForm bean for this request (if any) * @param request The HTTP request we are processing * @param response The HTTP response we are creating * @param parameter The <code>ActionMapping</code> parameter's name * Contains prefix of submit button names, or several prefixes * separated by comma or semicolon. * * @return The handler method name. */ protected String getMethodName(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String parameter) throws Exception { // If event prefix is not provided in action mapping parameter, // use default dialog prefix if (parameter == null || parameter.length() == 0) { parameter = DialogConstants.DIALOG_EVENT_KEY; } return super.getMethodName(mapping, form, request, response, parameter); } /** * Process the specified HTTP request, and create the corresponding HTTP * response (or forward to another web component that will create it). * Return an <code>ActionForward</code> instance describing where and how * control should be forwarded, or <code>null</code> if the response has * already been completed. * * @param mapping The ActionMapping used to select this instance * @param form The optional ActionForm bean for this request (if any) * @param request The HTTP request we are processing * @param response The HTTP response we are creating * * @exception java.lang.Exception if an exception occurs */ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // Is this an input process with POST? boolean isInput = isInput(request); // Is this initialization? Can be GET or POST. boolean isInit = isInput ? false : isInit(request); // Is this a bogus GET? Can be a first GET, containing JSESSIONID boolean isBogus = isInput || isInit ? false : isBogusGET(request); // Data input via POST: clean messages, dispatch to handler if (isInput || isInit || isBogus) { // Clear error messages before updating the accounts or on init. clearMessages(request); // If current request is bogus, actionForward will stay null, // and action will redirect to itself, thus cleaning up request. ActionForward actionForward = null; // Dispatch submit event if (!isBogus) { actionForward = super.execute(mapping, form, request, response); } // If mapping with DialogConstants.DIALOG_RELOAD_KEY is not defined, // build ActionForward object and redirect to self. Works if // actions use default ".do" suffix. if (actionForward == null) { // Appending ".do" suffix to redirect to itself String mappingPath = mapping.getPath(); if (!mappingPath.endsWith(getActionSuffix())) { mappingPath += getActionSuffix(); } // Action redirect return new ActionForward(DialogConstants.DIALOG_RELOAD_KEY, mappingPath, true /* REDIRECT */); // Has proper redirecting location } else if ( actionForward.getRedirect()) { return actionForward; // Patch location to use redirection } else { // MUST redirect on reload // to avoid recursive requests by switching from POST to GET return new ActionForward(actionForward.getName(), actionForward.getPath(), true /* REDIRECT */); } // View is requested via GET: do not clean anything, show dialog page } else { return getDialogView(mapping, form, request, response); } } /** * Returns an <code>ActionForward</code> instance describing the View * for current dialog state, usually a forward to a JSP page. * <p> * If you want to use the default implementation, define the View * under "DIALOG-VIEW" name in <forward> element of your action * mapping. * <p> * To use different mapping name, define the view in <forward> * element of your action mapping, and override this method to return * ActionForward object for your mapping name. * * @param mapping The ActionMapping used to select this instance * @param form The optional ActionForm bean for this request (if any) * @param request The HTTP request we are processing * @param response The HTTP response we are creating * * @exception java.lang.Exception if an exception occurs * @return ActionForward instance describing the View for dialog state */ public ActionForward getDialogView(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return mapping.findForward(DialogConstants.DIALOG_VIEW_KEY); } } --- NEW FILE: DialogConstants.java --- /* * Copyright 2004-2005 Michael Jouravlev. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jspcontrols.dialogs.actions; /** * Dialog constants, used in Struts Dialogs package. * * @author Michael Jouravlev */ public interface DialogConstants { /** * Default prefix for dialog events, like submit button names. */ String DIALOG_EVENT_KEY = "DIALOG-EVENT"; /** * The default View mapping for dialog. A dialog may have one or several * Views and view mappings. * <p> * If the dialog has only one view mapping, and you want to use default * view mapping name, define the View path using "DIALOG-VIEW" name * in <forward> element of your action mapping. */ String DIALOG_VIEW_KEY = "DIALOG-VIEW"; /** * The default reload mapping for dialog. A dialog redirects to reload * location. * <p> * If the dialog redirects to itself (default), then reload mapping can * be omitted in the action mapping. */ String DIALOG_RELOAD_KEY = "DIALOG-RELOAD"; /** * The default name of the action mapping "forward" element, describing * the location where the dialog should directed after a user canceled it. * <p> * If you want to use default cancel mapping name, define the cancel path * using "DIALOGCANCEL" name in <forward> element of your action mapping. */ String DIALOG_CANCEL_KEY = "DIALOG-CANCEL"; /** * The default name of the action mapping "forward" element, describing * the location where the dialog should directed after it completes. * <p> * If you want to use default done mapping name, define the path * using "DIALOGDONE" name in <forward> element of your action mapping. */ String DIALOG_DONE_KEY = "DIALOG-DONE"; } --- NEW FILE: SelectAction.java --- /* * Copyright 2004-2005 Michael Jouravlev. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jspcontrols.dialogs.actions; import org.apache.struts.actions.DispatchAction; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionForward; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.ServletException; import java.util.Map; import java.util.Enumeration; import java.util.StringTokenizer; /** * <p>An abstract <strong>Action</strong> that dispatches * an HTTP form submission event to a handler method.</p> * * <p>The purpose of this class is processing submission of HTML forms. * Unlike <nop>DispatchAction and <nop>LookupDispatchAction, which correlate * <code>value</code> attribute of <code>submit</code> form element with * handler method, this class uses <code>name</code> attribute. * Using <code>name</code> attribute allows to display a user-friendly caption * on a submit button. Also, it is possible to change button caption without * rebuilding the application.</p> * * <p>The subclass must define a map, which correlates submit button names * with method names, and handler methods themselves. Each method must have * the same signature as <code>execute</code> method. Subclass should not * redefine <code>execute</code> method.</p> * * <img border="0" align="center" src="doc-files/selectaction.gif" width="485" height="540"> * * <p>Using <code>name</code> attribute has a flip side: * during reset/populate/validate process, Struts assigns request values * to corresponding properties of a form bean. Thus, button keys must be named * differently from other request attributes. Also, the dispatch action * must recognize situation when no submit buttons were activated.</p> * * <p>Therefore, all submit buttons use a prefix in their name. * The prefix is specified by <code>parameter</code> property * of the <nop>ActionMapping. Make sure that you do not use periods * in the prefix and in actual button names, or Struts will try to search * and set the nested property and most likely will throw exception.</p> * * <p><strong>Example of Usage</strong></p> * * <p>The action should be configured in <code>struts‑config.xml</code> * file like this:</p> * <pre> * <action path="/test" * type="org.example.MyAction" * scope="request" * parameter="<b>myapp-submit</b>"/> * </pre> * <p>where: * <ul> * <li><code>org.example.MyAction</code> extends <code>SelectAction</code>; * <li><code>parameter</code> contains prefix of your choice for all * submit buttons on an HTML form. * </ul> * </p> * <p> * The names of submit elements should start from the aforementioned prefix, * for example: * </p> * <pre> * <form action="http://myhost/myapp/test.do" method="post"> * <input type="submit" name="<b>myapp-submit</b>-button-add" value="Add button"/> * <input type="submit" name="<b>myapp-submit</b>-button-delete" value="Fancy Delete button"/> * </form> * </pre> * <p>The subclass of <nop>SelectAction class must implement * <code>getKeyMethodMap</code> method, which defines mapping from button names * to method handlers, like this:</p> * <pre> * protected Map getKeyMethodMap() { * Map map = new HashMap(); * map.put("myapp-submit-button-add", "add"); * map.put("myapp-submit-button-delete", "delete"); * return map; * } * </pre> * <p>The subclass also must implement the methods themselves. For example:</p> * <pre> * public ActionForward add(ActionMapping mapping, * ActionForm form, * HttpServletRequest request, * HttpServletResponse response) * throws IOException, ServletException { * // do add * return mapping.findForward("success"); * } * * public ActionForward delete(ActionMapping mapping, * ActionForm form, * HttpServletRequest request, * HttpServletResponse response) * throws IOException, ServletException { * // do delete * return mapping.findForward("success"); * }</pre> * <p> * <strong>Notes</strong> * <ul> * <li>Subclass should not redefine <code>execute</code> method. * <li>If duplicate values exist for the keys returned by * <code>getKeyMethodMap</code>, the first one will be returned. * If no corresponding key is found then an exception will be thrown. * <li>Cancel button must be handled by implementing standard * <code>cancelled</code> method. * <li>According to HTML specification, at most one submit element is sent * from browser to the server when form is submitted. If form is submitted * without explicitly clicking a button, the result depends on a browser. * Either no buttons are submitted, or the first button defined on the form * is submitted. You need to override <code>unspecified</code> method * to handle default submits. * </ul> * </p> * * @author Michael Jouravlev */ public abstract class SelectAction extends DispatchAction { /** * Request-key-to-method-name map */ protected Map keyMethodMap = null; /** * Builds a request param / method name map. Called only once for * each instance of this class. This is a helper method, which * should not normally be redefined by a subclass. */ synchronized protected void buildLookupMap() throws ServletException { // key/method map is not yet initialized if (this.keyMethodMap == null) { Map keyMethodMap = getKeyMethodMap(); if (keyMethodMap != null) { this.keyMethodMap = getKeyMethodMap(); } else { // key/method map is not defined in a subclass // // Uncomment this, if this action is included in // official Struts bundle; make sure that // LocationStrings.properties contains // dispatch.keyMethodMap.isnull key // String message = messages.getMessage( // "dispatch.keyMethodMap.isnull", this.clazz.getName()); // Delete this if action is included in Struts bundle String message = "Dispatch action " + this.clazz.getName() + " returned null key/method map from getKeyMethodMap method"; throw new ServletException(message); } } } /** * Returns the method name, given a prefix and a request object. * This is a helper method, which should not normally be redefined * by a subclass. * * @param mapping The ActionMapping used to select this instance * @param form The optional ActionForm bean for this request (if any) * @param request The HTTP request we are processing * @param response The HTTP response we are creating * @param parameter The <code>ActionMapping</code> parameter's name * Contains prefix of submit button names, or several prefixes * separated by comma or semicolon. * * @return The handler method name. */ protected String getMethodName(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String parameter) throws Exception { // Find request parameter, starting with prefix. For example, // "myapp-submit-button-add" parameter fits "myapp-submit" prefix . String keyName = null; Enumeration reqEn = request.getParameterNames(); outmost: while(reqEn.hasMoreElements()) { String reqName = (String) reqEn.nextElement(); StringTokenizer params = new StringTokenizer(parameter, ",; "); while (params.hasMoreTokens()) { String buttonPrefix = params.nextToken(); if (reqName.startsWith(buttonPrefix)) { keyName = reqName; // If using image button, strip coordinates int imageButtonXPos = keyName.indexOf(".x"); if (imageButtonXPos > 0) { keyName = keyName.substring(0, imageButtonXPos); } else { int imageButtonYPos = keyName.indexOf(".y"); if (imageButtonYPos > 0) { keyName = keyName.substring(0, imageButtonYPos); } } // For image button there can be two or even three parameters: // MSIE: name.x=xcoord&name.y=ycoord // Firefox: name.x=xcoord&name.y=ycoord&name=value // // We will use only one parameter. Also notice, that MSIE // does not pass value of image button. This is another // good reason for using "name" attribute for dispatching. break outmost; } } } // If button is not be recognized, method will return null. // DispatchAction will call "unspecified" method. String methodName = null; // Button recognized if (keyName != null) { // Build param name to method map if it is not built yet buildLookupMap(); // Pull out a method name for request parameter Object mappedObj = keyMethodMap.get(keyName); if (mappedObj == null || !(mappedObj instanceof String)) { // Uncomment this, if this action is included in // official Struts bundle; make sure that // LocationStrings.properties contains // dispatch.keyMethodMap.notstring key // String message = messages.getMessage( // "dispatch.keyMethodMap.notstring", // mapping.getPath(), keyName); // Delete this if action is included in Struts bundle String message = "Dispatch action " + mapping.getPath() + " returned null or non-string method name" + " for request key " + keyName; throw new ServletException(message); } methodName = (String) mappedObj; return methodName; } return methodName; } /** * Method which is dispatched to when corresponding handler method * is not found for an activated submit button. Subclass should * override this method if it wish to provide default behavior different * than throwing a ServletException. */ protected ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String message = messages.getMessage( "dispatch.method", this.clazz.getName(), "unspecified"); log.error(message); throw new ServletException(message); } /** * Provides the mapping from the <code>name</code> attribute of * a submit button to method name. For example: * <br><pre> * protected Map getKeyMethodMap() { * Map map = new HashMap(); * map.put("myapp-submit-button-add", "add"); * map.put("myapp-submit-button-delete", "delete"); * return map; * }</pre> * This method is must be implemented in a subclass. * * @return Map, containing association between submit button name and * a handler method. Map keys must start from a prefix, * defined in <code>parameter</code> property of the action mapping. Map * values must contain names of handler methods. Each handler method must * have the same signature as <code>execute</code> method. */ protected abstract Map getKeyMethodMap(); } --- NEW FILE: package.html --- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <html> <head> <title>net.jspcontrols.dialogs.actions package</title> <!-- Copyright 2004-2005 Michael Jouravlev. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> </head> <body> Provides actions to support dialogs and wizards. <!-- Last updated: Tue, June 07 2005 --> </body> </html> |