Action is action method defined in action class, mapped to some URL - action path. Madvoc uses naming convention (CoC) and annotations to define action path from action method. By default, action path is built from package, class and method name of an action or its annotations, using the following convention:
action path = /<action_package>/<action_class>.<action_method>.<extension>
extension - default extension value (equals to "html"), part of global Madvoc configuration;action_method - part of the action path that comes from action method, by default it is method name;action_class - part of the action path that comes from action class, by default it is un-capitalized class name with the last word stripped;action_package - optional part of the action path that comes from action's package.By default, each part of path is defined from method/class/package name. Still, each can be explicitly defined by setting corresponding annotation value.
Bare minimum for creating an action is to put annotations on POJO class and one of its methods:
@MadvocAction
public class HelloAction {
@Action
public void world() {
}
}This action class and action method is mapped to the following action path: /hello.world.html. As said, each part
of action path may be set explicitly in annotations, so the following action:
@MadvocAction("holla")
public class HelloAction {
@Action("mundo")
public void world() {
}
}is mapped to /holla.mundo.html. Moreover, since action action paths built by simple string concatenation,
it is possible to set more complex paths using annotations:
@MadvocAction("foo/boo")
public class HelloAction {
@Action("zoo/hello.exec")
public void world() {
}
}This action is mapped to: /foo/boo.zoo/hello.exec.html.
One side-note: one action class may defined more then one actions (action methods).
It sounds reasonable that most of the website's action paths end with the same extension.
Therefore, the default extension is defined once in global Madvoc configuration. However, it is still possible to set
custom extension using @Action annotation's element 'extension':
@MadvocAction
public class HelloAction {
@Action(extension="jpg")
public void world() {
}
@Action(extension=Action.NO_EXTENSION)
public void foo() {
}
}The first action is mapped to: /hello.world.jpg. The second one is mapped to: /hello.foo.
Action's extension is either default one or one defined by @Action element 'extension'.
Since Madvoc is very extensible, it is also possible to extend its component dedicated for action path registration
and to implement custom behavior. For example, it is easy to make that any method that starts with store... has extension .do
instead of default one.
To override Madvoc action naming convention, it is possible to specify full action path in the annotation by using the prefix '/':
@MadvocAction
public class HelloAction {
@Action("/bonjour-monde.html")
public void world() {
}
}Obviously, this action is mapped to /bonjour-monde.html. When action path defined in @Action starts with
'/' it is considered as full action path and all other names (class name, extension) are ignored.
When full action path is specified, Madvoc will not append default extension nor custom one (defined in @Action's element 'extension').
By default, packages are ignored and not used for building action paths. Nevertheless, it make sense to group several action paths (i.e. action classes) in one folder (i.e. package). Madvoc provides way how to consider packages when building action paths.
First, this feature must be turned on by setting the root package, one that will be mapped to the web root. This is done during Madvoc initialization (what is not the current subject):
public class MyWebApplication extends WebApplication {
@Override
protected void init(MadvocConfig madvocConfig, ServletContext servletContext) {
madvocConfig.setRootPackageOf(IndexAction.class);
}
}
Root package may be given as a string, but above is presented more convinient alternative: to specify it using any action class from
the web root (usually IndexAction).
When this feature is active, Madvoc will consider packages of action classes: the offset from root package will be used as action path prefix. So, packages will be mapped as folders. The following action:
package org.jodd.madvoc.doc;
@MadvocAction
public class HelloAction {
@Action
public void world() {
}
}is mapped to /doc/hello.world.html (if root package is set to: org.jodd.madvoc).
Only one root package can be specified, so, when this feature is active, actions that are not beneath root package will have long action paths (built from complete package name), what most probably is not the desired intention.
Moreover, it is possible to specify custom action package using @MadvocAction annotation on package (in package-info.java).
It is also possible to override package annotation value with @MadvocAction annotation of action class: if its value starts with '/'
then package value is ignored.
Sometimes developer wants to group some action classes in separate subpackage, but doesn't want to change the action path (e.g. the root path).
By specifing @MadvocAction("/") on sub-packages Madvoc will map all containing classes to the web root, as they were there and not in the sub-package:
@MadvocAction("/")
package com.....;
import jodd.madvoc.meta.MadvocAction;
By default, Madvoc will ignore value of HTTP request method. No matter if it is POST, GET or other, mapped action method will be invoked.
If needed, Madvoc offers more control considering HTTP methods: it allows to specify one for action method, using @Action
annotation's element 'method':
@MadvocAction
public class FormAction {
@Action(method = "POST")
public void store() {
}
}This action method is mapped to /form.store.html and will be invoked only for POST HTTP request methods. GET and others
will simply return error 404 (page not found).
When HTTP method is specified, Madvoc will register such action path with appended http method information. Action from above example is therefore mapped to: /form.store.html#POST.
When looking up for the action path among registered once, Madvoc first tries to find action path with specified HTTP method. If such action path does not exist, Madvoc will lookup for action path with no HTTP method information.
Similar as for extensions, it is possible to extend Madvoc to programatically specify HTTP method to actions that match some custom criteria.
Nice practice is to specify the extension such as 'do' using @Action annotation to all actions that are mapped to POST request (i.e. form submissions) and then to
programatically set POST for those actions, and GET to all others; if it is not explicitly set different.
As seen, Madvoc uses action method name (or annotation value) for creating action path. Moreover, it is possible to have action path that doesn't include action method name - what is often needed for 'common' pages (such as index.html, about.html, error.html). By default, Madvoc will ignore action method name for methods named as
execute and view. Such action methods are so-called the default ones. So, the following action:
@MadvocAction
public class IndexAction {
@Action
public void view() {
}
}is mapped simply to: /index.html. If more than one default method name is used, Madvoc will either take the last one,
or will throw an exception indicating duplicated action paths (depending on configuration). Furthermore, default action names are
part of global Madvoc configuration and can be customized as needed.
Alternatively, @Action annotation has the boolean element 'notInPath' that can be used for the same purpose
on any action method. Therefore, following action has the same action path mapping:
@MadvocAction
public class IndexAction {
@Action(notInPath = true)
public void foo() {
}
}
By default, when some non-registered action path is requested, Madvoc returns error 404. All pages, including the static ones, must have registered its own action method. This is especially repetitive for static pages, such as for documentation and so on: each page would require an action class with one default action method that returns void.
Madvoc provides so called 'supplement actions' for this situations. Supplement action is an action class with default action method that will be registered as action handler for each requested non-registered action path that ends with default extension. First time when non-registered action path is requested, Madvoc will register supplement action for that action path.
This feature is by default turned off. It can be turned on in the Madvoc configuration:
public class MyMadvocConfig extends MadvocConfig {
public MyMadvocConfig() {
supplementAction = DefaultActionSupplement.class;
}
}
For every non-registered action path, such as /foo.html, Madvoc will register supplement action (here that is DefaultActionSupplement) as its action handler. Since default supplement action returns void, in practice that means that requesting /foo.html will automatically redirect to /foo.jsp.
Using supplement actions is a potential critical memory-leak issue! Madvoc will add and keep registration info for every requested previously non-registered action path. Malicious user may request infinite number of previously non-registered pages and for each Madvoc will add new registration info. This would constantly increase used memory by some small value, eventually ending with out of memory exception.
Because of this issue, supplement actions should be used with care. Furthermore, similar effect can be achieved with Madvoc using other techniques, such as url rewriting etc.
Note that supplement actions are only required if there is a need to render JSP page via Madvoc. But there is an alternative, when just static pages are used - simply do nothing and use HTML pages. When an action request is not processed by Madvoc, then request will be simply passed to servlet container.
It is possible to reference default names in name values of the Madvoc annotations. For example, when specifying the full action path it is possible to reference the default extension, allowing it to be no more hard-coded in the action string:
@MadvocAction
public class HelloAction {
@Action("/bonjour-monde.${ext}")
public void world() {
}
}In this action path value, extension macro '${ext}' will be replaced with default Madvoc extension. The following macros are available:
${package} - replaces default package name in package-level annotations;${class} - replaces default class name in class-level annotations;${method} - replaces default method name in method-level annotations;${ext} - replaces default extension in 'extension' and 'value' elements of method-level annotations.Following table summarize default behavior of ActionMethodParser - Madvoc component
dedicated for building action paths from registered actions.
| package | class | method | action path |
| * | * | /foo | /foo |
| * | * | /foo.ext | /foo.ext |
| * | /boo | foo | /boo.foo.html |
| * | /boo | foo.ext | /boo.foo.ext.html |
| (none) | boo | foo | /boo.foo.html |
| (none) | boo | view/execute | /boo.html |
| /zoo | boo | foo | /zoo/boo.foo.html |
By default, Madvoc parses action method (class and/or package) to build it's action path, during the registration. In that case it is necessary to provide and register all action methods before starting working with Madvoc. This can be done either automatically, either manually.
Madvoc provides reverse action path mapping: mapping action paths to action methods. For every requested action path, Madvoc may try to find if there is a matching class and method, using simple convention rules. If such class and method is found, they will be registered as action method handler. Therefore, all registrations happens later, during the work of application. This process of mapping is reverse of default mapping.
To enable this feature, two things must be set:
public class MyMadvocConfig extends MadvocConfig {
public MyMadvocConfig() {
actionPathMappingEnabled = true;
setRootPackageOf(IndexAction.class);
}
}
The following action path mapping convention id defined by ActionPathMapper:
| actionPath | action signature |
| /zoo/boo.foo.html | zoo.Boo#foo |
| /zoo/boo.foo.ext | zoo.Boo#fooExt |
| /zoo/boo.html | zoo.Boo#view |
| /zoo/boo.ext | zoo.Boo#viewExt |
| /zoo/boo | zoo.Boo#execute |
Here 'html' denote default extension, 'ext' denote any non-default extension. Method names 'view' and 'execute' are actually first and second default action name, defined in global Madvoc configuration. Of course, if there are less or none default action name, Madvoc will fail-back to the existing name.