An ActionResolver that uses the names of classes and methods to generate sensible default URL bindings and event names respectively. Extends the default {@link AnnotatedClassActionResolver}, and is fully backward compatible. Any classes and methods that are annotated with {@link net.sourceforge.stripes.action.UrlBinding} and{@link net.sourceforge.stripes.action.HandlesEvent} will retain the bindings specified inthose annotations. In the case when an annotation is absent then a default binding is generated.
The generation of ActionBean URL bindings is done by taking the class name and removing any extraneous packages at the front of the name, removing the strings "Action" and "Bean" from the end of the name, substituting slashes for periods and appending a suffix (.action by default). The set of packages that are trimmed is specified by the {@code getBasePackages()} method. By default this method returns the set[web, www, stripes, action]. These packages (and their parents) are removed from the class name. E.g. {@code com.myco.web.foo.BarActionBean} would become {@code foo.BarActionBean}. Continuing on, the list of Action Bean suffixes, specified by the {@code getActionBeanSuffixes()}method, are trimmed from the end of the Action Bean class name. With the defaults, [Bean, Action], we would trim {@code foo.BarActionBean} further to {@code foo.Bar}, and then translate it to {@code /foo/Bar}. Lastly the suffix returned by {@code getBindingSuffix()}is appended, giving the binding {@code /foo/Bar.action}.
The translation of class names into URL bindings is designed to be easy to override and customize. To that end you can easily change how this translation is done by overriding {@code getBasePackages()} and/or {@code getBindingSuffix()}, or completely customize the behaviour by overriding {@code getUrlBinding(String)}.
Mapping of method names to event names is simpler. Again the parent class is delegated to in case the method is annotated. If it is not, and the method is a concrete public method that returns a Resolution (or subclass thereof) it is mapped to an event of the same name as the method. So an un-annotated method " {@code public Resolution view()}" is mapped to an event called "view". It should be noted that there is no special method name that signifies the default handler. If there is more than one handler and you require a default handler you must still mark the default method with {@code @DefaultHandler}.
Another useful feature of the NameBasedActionResolver is that when a request arrives for a URL that is not bound to an ActionBean the resolver will attempt to map the request to a view and return a 'dummy' ActionBean that will take the user to the view. The exact behaviour is modifiable by overriding one or more of {@link #handleActionBeanNotFound(ActionBeanContext,String)}, {@link #findView(String)} or{@link #getFindViewAttempts(String)}. The default behaviour is to map the URL being requested to three potential JSP names/paths, check for the existence of a JSP at those locations and if one exists then to return an ActionBean that will render the view. For example if a user requested '/account/ViewAccount.action' but an ActionBean does not yet exist bound to that URL, the resolver will check for JSPs in the following order:
The value of this approach comes from the fact that by default all pages can appear to have a pre-action whether they actually have one or not. In the above can you might chose to link to {@code /account/ViewAccount.action} even though you know that no action exists and you wantto navigate directly to a page. This way, if you later decide you do need a pre-action for any reason you can simply code the ActionBean and be done. No URLs or links need to be modified and all requests to {@code /account/ViewAccount.action} will flow through the ActionBean.
@author Tim Fennell @since Stripes 1.2
|
|
|
|