Every Mentawai action returns a String result that is used in the application manager to setup a corresponding Consequence. For example, you might want to allow an action to have two different consequences: one for browsers that need HTML through a JSP template and another one for Ajax requests that need JSON through a Ajax renderer. The action does not care how its output will be processed by the view layer. It can just check some client HTTP request header to return the appropriate result String.
TIP: Instead of doing this client check on every action, you may want to apply a global filter to take care of that.
Forward consequence:
@Override public void loadAction() { action("/Hello", HelloAction.class, "hi") .on(SUCCESS, fwd("/jsp/hello.jsp")); }
Redirect consequence:
// redirect to http://www.myapp.com/MYCONTEXT/congrats.jsp?param1=blah¶m2=foo .on(SUCCESS, redir("/congrats.jsp")); // context will be included, as well as any action output values // redirect to http://www.myapp.com/MYCONTEXT/Book.show.mtw?param1=blah¶m2=foo .on(SUCCESS, redir("/Book.show.mtw")); // context will be included, as well as any action output values // redirect to a dynamic URL coming from the action, also append any output parameters... .on(SUCCESS, redir()); // the url will be dynamically generated by the action // the action must do: output.setValue(Redirect.REDIRURL_PARAM, theUrlToRedir); // or the shorter version: redir(theUrlToRedir); // to include parameters you just add values to the action output... // if you don't add anything then no parameters are appended... output.setValue("param1", "blah"); output.setValue("param2", "foo"); // redirect to http://www.myapp.com/congrats.jsp .on(SUCCESS, redir("//congrats.jsp")); // context will NOT be included (rarely used!)
You can also redirect to an action config and Mentawai will build the URL from the ActionConfig object:
ActionConfig helloAction = action("/Hello", HelloAction.class, "hi") .on(SUCESS, redir("/jsp.hello.jsp")); action(UserAction.class, "add") // <=== same thing as action("/User", UserAction.class, "add") .on(SUCCESS, redir(helloAction)); // <=== a redir to http://www.mysite.com/MYCONTEXT/User.add.mtw will happen here...
Stream consequence:
To return an image or any binary file you can do:
// in the action: public class ImageAction extends BaseAction { public String send() { byte[] image = getImageBytesSomehow(); output.setValue(StreamConsequence.STREAM, image); output.setValue(StreamConsequence.CONTENT_LENGTH_KEY, image.length); // OR the shorter version: stream(image, image.length); return SUCCESS; } } // in the application manager: .on(SUCCESS, stream("image/jpg"));
To return a file from an InputStream you can do:
// in the action: public class PDFAction extends BaseAction { public String execute() { FileInputStream fis = new FileInputStream("review.pdf"); // NOTE: A FileInputStream has no size to set with the response... output.setValue(StreamConsequence.STREAM, fis); output.setValue(StreamConsequence.FILENAME, "review.pdf"); // OR the shorter method: stream(fis, "review.pdf"); return SUCCESS; } } // in the application manager: .on(SUCCESS, stream("application/pdf"));
Ajax consequence:
Ajax is very important and will be discussed on its own section, but here is how it is basically done:
// in the action: public class TestAction extends BaseAction { public String autoCompleter() { String sourceInput = input.getStringValue("sourceInput"); Map<Integer, String> map = new LinkedHashMap<Integer, String>(); if(sourceInput.startsWith("a")) { map.put(1, "a. Somebody with id 1"); map.put(2, "a. Somebody with id 2"); map.put(3, "a. Somebody with id 3"); } else if(sourceInput.startsWith("b")) { map.put(4, "b. Somebody with id 4"); map.put(5, "b. Somebody with id 5"); map.put(6, "b. Somebody with id 6"); } else { map.put(7, "*. Somebody with id 7"); map.put(8, "*. Somebody with id 8"); map.put(9, "*. Somebody with id 9"); } ajax(map); return SUCCESS; } } // in the application manager: .on(SUCCESS, ajax()); // the default Ajax consequence that will renderer the map as JSON
Setting a global consequence:
You can also set a consequence that will be checked for ALL actions. That's very useful when a global filter might return a result that you want to trap and apply a consequence on a global level.
@Override public void loadFilters() { filter(new AuthenticationFilter()); // a global authentication filter on(LOGIN, redir("/jsp/login.jsp")); // a global consequence }