Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

NOTE: the actionName value must specify the name of your action as defined in the struts.xml action mapping, not necessarily your action class name. the desiredMenu attribute is just the name of the menu, which currently only has options for "editor" and "admin".

Exception and Error

...

/Message Handling

One of the biggest changes with the struts2 migration is going to be how Roller handles errors and exceptions. The old struts1 code did a pretty poor job of properly handling exceptions and with the struts2 migration that is changing. There is really only one significant change happening, but it's a big one, with the new struts2 actions all actions must catch their own exceptions and deal with them somehow. It is no longer acceptable to define an action method as "public String execute() throws Exception".

Luckily, now that we are using struts2 it's a little bit easier to report errors on your action so hopefully that will make it easier and more encourageable for action writers to properly handle errors. To define an error on a struts2 action all you need to do is call the addError() method and you are done. The addError() method has 2 forms, one which simply accepts a bundle key, the other which accepts a bundle key and an optional parameter ...

No Format

    public void addError(String errorKey);
    
    public void addError(String errorKey, String param);

Same goes for message notifications as well ...

No Format

    public void addMessage(String msgKey);
    
    public void addMessage(String msgKey, String param);

So setting errors/messages to display on the UI is now as easy as it's every going to be and there are no more excuses for being lazy and simply throwing your exceptions out of your action method for something else to handle.

Migration Walkthrough

Assuming that you have read through and understand the basic design of how Roller uses struts2 and you are ready to try migrating some of the code, this walkthrough can serve as a decent starting point and helper to show you what you are getting into. Of course, this is only a best effort guide and each action will have it's own quirks and gotchas which may not be covered here. If that's the case then try to sort it out and if you can't then ask about it on the Roller dev list.

Migrating Actions

Here are some notes on the series of steps that you might run through to migrate an existing Roller struts1 action to a new struts2 action. The specific details of the work will vary depending on the situation.

  • copy old action code to new action class and rename (makes things less confusing)
  • make sure new package name is appropriate at the top of your copied code
  • have class extend UIAction
  • define security needs of your action.
    • remove all attempts to get authenticated user via RollerSession and replace with a simple call to getAuthenticatedUser(). access to the authenticated UserData object is provide for you by having your action extend the UIAction class, so there is nothing that you need to do. by default, all actions require an authenticated user, so if the user is not properly authenticated when trying to access an action then they will get an access denied page.
    • remove all attempts to get the weblog used by the action via a RollerRequest object and replace with a simple call to getActionWeblog(). just like above, this is extracted from the request and populated for you.
    • to see how you can control the security options for your action, read the Security Enforcement section above.
  • fix action method declarations
    • action methods now return just a String instead of an ActionForward
    • action methods now do not accept any params
    • action methods do not throw any exceptions (handle these inside your action method!)
  • fix action method return statements to just return a String instead of an ActionForward
  • fix up error/message handling
    • delete all instances of ActionMessages() and ActionErrors()
    • delete all calls to saveMessages() and saveErrors()
    • replace all attempts to set action messages/errors with calls to addMessage(key), addMessage(key, param), addError(key), and addError(key, param). these methods are convenience methods built into the UIAction class which make it trivial to set errors and messages which will automatically get rendered on the page.
  • fix up handling of submitted data

Migration Walkthrough

Migrating Actions

Here are some notes on the series of steps that you might run through to migrate an existing Roller struts1 action to a new struts2 action. The specific details of the work will vary depending on the situation.

  • copy old action code to new action class and rename (makes things less confusing)
  • make sure package name is appropriate at the top of your copied code
  • extend UIAction (MigratingUIAction if request object is really needed, but try not to)
  • define security needs of your action.
    • remove all attempts to get authenticated user via RollerSession and replace with a simple call to getAuthenticatedUser(). access to the authenticated UserData object is provide for you by having your action extend the UIAction class, so there is nothing that you need to do. by default, all actions require an authenticated user, so if the user is not properly authenticated when trying to access an action then they will get an access denied page.
    • remove all attempts to get the weblog used by the action via a RollerRequest object and replace with a simple call to getActionWeblog(). just like above, this is extracted from the request and populated for you.
    • to see how you can control the security options for your action, check out the UISecurityEnforced interface which provides control points. this interface is implemented by the UIAction class which you most likely should be extending, so you can modify the default behavior by simply overriding any of the methods from that interface in your action class.
  • fix action method declarations to
    • return just a String
    • not accept any params
    • not throw any exceptions (handle these inside your action method!)
  • fix action method results to just return a String instead of an ActionForward
    • if your action handles a lot of fields then define a class level attribute called "bean"
    with getters and setters.
    • which will serve as a form bean for your action and provide a getter and setter method. check out an existing example like the RegisterForm for an example.
    • if your action only needs to make use of a couple fields then you can just define those attributes directly in your action and provide getters and setters
    .
    • NOTE: if you are defining a "bean" in your action, make sure that the bean gets initiated. i.e. you can't define your bean as "MyBean bean = null" because that's not an initiated attribute. instead you should probably do this ... "MyBean bean = new MyBean()"
    • once that is done you need to change usages of the old action form.xxx() calls to getBean().xxx() or just xxx() if you didn't define a "bean".
    • now you can delete all old code which trys to extract the form bean from the passed in actionForm
    • .
    • NOTE: if you are defining a "bean" in your action, make sure that the bean gets initiated. i.e. you can't define your bean as "MyBean bean = null" because that's not an initiated attribute. instead you should probably do this ... "MyBean bean = new MyBean()"
    • once that is done you need to change usages of the old form.xxx() calls to getBean().xxx() or just xxx() if you didn't define a "bean".
    • you can also delete all old code which trys to extract the form bean from the passed in actionForm
    fix up error/message handling
    • delete all instances of ActionMessages() and ActionErrors()
    • delete all calls to saveMessages() and saveErrors()
    • replace all attempts to set action messages/errors with calls to addMessage(key), addMessage(key, param), addError(key), and addError(key, param). these methods are convenience methods built into the UIAction class which make it trivial to set errors and messages which will automatically get rendered on the page.
  • fix up form validation
    • if there is a custom validate() method then replace it with a no arg method myValidate()method myValidate(). it is very important that you don't leave a validate() method in your action because that is a struts2 specific method and will almost certainly cause behavior you didn't intend.
  • tidy up the action results.
    • try to use the defaults like SUCCESS and INPUT, and custom ones where applicable, like "cancel".
  • fix up use of "models" up use of "models"
    • models are no longer used with our struts2 actions. in struts2 your action is your model, so anything that was being used through a model class needs to be transferred into your action class. be selective here though, the old struts1 code provided lots of model methods which weren't really necessary
    • replace all attempts to set a "model" attribute on the request object with a call to setModel()
    • modify all custom "model" objects either just use UIModel or extend UIModel
    • NOTE: you may need to begin the process of migrating the jsps a bit in order to decide how much of the old model class you need to keep. it's entirely possible that once you rework the jsp a bit you'll find that most of the elements of the old model class are no longer needed.

Migrating JSPs

  • replace include for taglibs.jsp to taglibs-struts2.jsp
  • do a search and replace for "fmt:message key" with "s:text name"
  • replace html:form with s:form and delete the method param
  • change the new s:form action attribute to the correct action name, like myAction!method
  • replace instances of "html:text property" with "s:textfield name"
  • add "bean." in front of all name attributes for form fields if you are using a "bean".