Adding new actions

First, let's create a new package to separate the new code: if you are using eclipse, go to the src folder, right click, create new package. Name it org.mumtutorial.action.event.

To create a new Event you will need to create two new Action classes:

  1. org.mumtutorial.action.event.CreateEvent will display the form to input the data
  2. org.mumtutorial.action.event.SaveEvent will take care of the input values and actually create the new Event Object in the repository.

Every action in MUM must have the org.mum.action.BasicAction as superclass. This superclass has a lot usefull code to make our job simpler.

In Eclipse the screen is like that:

Don't forget to check "Constructors from superclass", so it does this job for you. Repeat the step to create SaveEvent action.

Dependency injection via constructors

You'll probably notice that the BasicAction's constructor needs two parameters. Just create your actions with the same constructor arguments and the required objects will be injected to the actions, much like your Model creator was injected to the model creation phase.

Authorization later

We'll deal with authorization on chapter four. For now, you'll allow everybody to do everything. For that you need to override the abstract method called authorize from the superclass BasicAction and make it always return true. Be careful if using Eclipse, it will create the default override code for you, but by default the function will return false. Remember to change it to true.

Anyway, the final code should look like this:

@Override
public boolean authorize(String subject) throws EntityNotFoundException,
    TalosHibernateException {
    // TODO Auto-generated method stub
    return true;
}

Allow us some lazyness for better readability

When showing you code we will omit self-evident code like getters, setters and the authorization block from now on. You can get a package with all code from the tutorial here

The CreateEvent action

The first action (CreateEvent) basically will only be responsible to display the form and do some validation:

  • Is the required id sent in the request?
  • Does the author exist at all? Here, this is only validated by trying to load the PObject and providing a getter for it to pass the id to the form
  • Authorization will be handled in the next chapter. For now, let's allow everyone.

Here are the important bits of the action:


public class CreateEvent extends BasicAction {
    private PObject author;
    public CreateEvent(Repository repository, Talos talos) {
        super(repository, talos);
    }
    @Override
    public boolean authorize(String subject) throws EntityNotFoundException,
      TalosHibernateException {
        return true;
    }
    public boolean isValid() {
        if(isNull(this.author)){
            addFieldError("author","cannot be empty");
            return false;
        }
        return true;
    }
    public PObject getAuthor() {
        return author;
    }
    public void setAuthor(PObject author) {
        this.author = author;
    }
}

Nothing really special here, though.

The SaveEvent action

When saving the event a little more effort is needed, namely a little larger validation if all required parameters are sent must happen and of course there is some business logic needed for the object creation. That is, a new Object needs to be created and filled with values.


public class SaveEvent extends BasicAction implements ObjectModelDriven{
    private PObject event;
    public SaveEvent(Repository repository, Talos talos) {
        super(repository, talos);
    }
    @Override
    public String execute() throws Exception {
        getRepository().commit();
        return SUCCESS;
    }
    public boolean isValid() {
        boolean result = true;
        if(isNull(event)){
            addActionError("Event cannot be null");
            return false;
        }
        if(isNull(event.get("author"))){
            addActionError("Author cannot be empty");
            return false;
        }
        String title = event.get("title");
        if(isNullOrEmpty(title)){
            addFieldError("event.title","cannot be empty");
            result = false;
        }
        if(isNull(event.get("date"))){
            addFieldError("event.date","cannot be empty");
            result = false;
        }
        if(isNull(event.get("time"))){
            addFieldError("event.time","cannot be empty");
            result = false;
        }
        return result;
    }
  @Override
    public boolean authorize(String subject) throws EntityNotFoundException,
    TalosHibernateException {
        return true;
    }
    public PObject getAuthor() {
        return event.get("author");
    }
    public PObject getEvent() {
        return event;
    }
    @Translated(type = "Event", operation = OperationType.New)
    public void setEvent(PObject event) {
        this.event = event;
    }
}

Don't forget to include in your imports:

import org.mum.interceptor.ObjectModelDriven;
import org.mum.webwork.converter.OperationType;
import org.mum.webwork.converter.Translated;

What's happened?

Here you can learn more about how the ObjectModelDriven interceptor works. First you have to make your class implement the ObjectModelDriven interface. Then create the setter that will be used for the interceptor to fill the PObject with form values. This setter must have an annotation called @Translated that informs the PObject and operation types. Here we are dealing with Type "Event" and the operation is "New" (create).

Wiring the new action in XWork

To use the new action we have to specify where it should be visible in the web application. Webwork uses XWork to map actions to URLs so, we will need to edit config/xwork.xml.

Since events are a topic which has not been touched before in MUM we will create a new package called "event" whose namespace will be /event:

<package name="event" namespace="/event" extends="mum-default">
</package>

Inside the package, we map our two actions, telling Webwork what to do when an action finishes with SUCCESS or INPUT. Other possible errors are mapped on the top in a tag <global-results>. The mapping for create tells xwork to show the template when SUCCESS happens and an error message when the validation fails:

<action name="create" class="org.mumtutorial.action.event.CreateEvent">
   <result>create.ftl</result>
   <result name="input" type="chain">error</result>
</action>

In the case of save, the validation means that the user must submit the form again, maybe with some corrections, so we chain to the create action if INPUT occurs:

<action name="save" class="org.mumtutorial.action.event.SaveEvent">
   <result>save.ftl</result>
   <result name="input" type="chain">create</result>
</action>

Since both actions are declared inside the package with a namespace /event, they will be called when a request is sent to the server that uses a URL like http://server:port/{base}/event/create.action, where base is the application context name. Please consult the WebWork manual for further details.

When you relaunch MUM, you'll be able to create new events.

Please send us comments, questions, criticism:

Please send us comments, questions, criticism!