Apache Struts 2 Documentation > Upgrading from 1.4 |

Apache Struts 2 Documentation
Upgrading from 1.4
Edit Page Browse Space Add Page Add News
Added by mgreer, last edited by Ted Husted on Feb 12, 2007 (view change)

### Package changes

Webwork1.x was seperated into two projects, XWork and Webwork. From this, several classes have been moved to different package names.

- ActionSupport has moved from webwork.ActionSupport to com.opensymphony.xwork.ActionSupport
  - doExecute() no longer exists, override execute()
  - the methods addError and addErrorMessage are now addFieldError and addActionError respectively

### Configuration changes

- actions.xml/views.properties needs to be converted to xwork.xml
  If you're using an actions.xml file to configure your webwork 1, you can use the attached XSLT to convert the actions.xml file to a vanilla xwork.xml file.
  To apply this XSLT, you'll need to do the following:
  Get a copy of the XSLT. You can find the latest version in CVS in webwork/src/etc/actions.xsl . Next, find yourself an XSLT rendering engine. Xalan is a good choice and can be found at http://xml.apache.org/xalan-j/index.html
  Finally, do the conversion.

    java org.apache.xalan.xslt.Process -IN actions.xml -XSL actions.xsl -OUT xwork.xml

Remember that you'll need to Xalan libraries in your classpath to run the above command.
If you want to look at these pages directly in your browser, I recommend user Internet Explorer as it automagically formats XML documents reasonably. There one caveat though. WW1 had a way to shorten the declaration of actions by allowing you to specify a package prefix in webwork.properties file. Since this information is outside the actions.xml file, the XSLT is unable to take advantage of it. Consequently, you might need to edit the xwork.xml file to update the class names.

WebWork 1.x configuration used a pull paradigm to load action configurations when they are asked for, whereas WebWork2 builds the configuration up-front to make the configuration queryable. The webwork.MigrationConfiguration must therefore act as an adapter between these two paradigms. It does this by returning a custom RuntimeConfiguration which first tries the default XWork Configuration (which, by default, loads configuration information from a file named "xwork.xml" in the root of the classpath) and then attempts to load action configuration using the Configuration classes from WebWork 1.x. In this way, an application can be slowly converted over to WebWork2 while reusing the configuration and Actions from a WebWork 1.x application. One caveat in this is that your migrated application MUST be rebuilt against the WebWork2 and migration jar files, as the classloader will rightly recognize that the webwork.Action and webwork.ActionSupport in WebWork 1.x are not the same as those provided by the migration jar files. Other than that, it should be seamless (and let us know if it isn't).

If the webwork.MigrationRuntimeConfiguration does not find the action configuration using the RuntimeConfiguration from the supplied RuntimeConfiguration (which is acquried from the Xwork DefaultConfiguration and will load configurations from all of the sources configured for XWork / WebWork2), it will build an ActionConfiguration by instantiating an Action using the ActionFactories from WebWork 1.x. The ActionFactory stack used is a subset of the default ActionFactory stack used in WebWork 1.x:

    factory = new JavaActionFactory();
            factory = new ScriptActionFactoryProxy(factory);
            factory = new XMLActionFactoryProxy(factory);
            factory = new PrefixActionFactoryProxy(factory);
            factory = new JspActionFactoryProxy(factory);
            factory = new CommandActionFactoryProxy(factory);
            factory = new AliasingActionFactoryProxy(factory);
            factory = new CommandActionFactoryProxy(factory);
            factory = new ContextActionFactoryProxy(factory);

Some of the ActionFactory classes have been left out as they are handled by Interceptors in WebWork2. If the Action instance is created (meaning that the configuration has been found in the webwork.properties or actions.xml files used by the WebWork 1.x configuration classes) a parameter Map is created by introspecting the Action instance. A Map is needed for results and, again, WebWork 1.x used a pull paradigm to find results when they were needed, so a LazyResultMap is created which extends HashMap and overrides get() to look up the Result configuration if it has not previously been loaded. If the result ends in the Action suffix (defaulting to ".action"), then a ChainingResult is created, otherwise a ServletDispatcherResult is created. Using the Action class of the instantiated Action, the Map of parameters introspected from the Action instance, and the LazyResultMap, a new ActionConfig is created. The ActionConfig is saved into a special Package, "webwork-migration", so that it will pick up the default Interceptor stack defined for that package. The "webwork-migration" package is defined in a webwork-migration.xml file which is included in the migration jar file and which is automatically added to the Xwork configuration providers when the MigrationConfiguration is used:

    <!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd">

    <xwork>
        <include file="webwork-default.xml"/>
        <package name="webwork-migration" abstract="true" extends="webwork-default">
            <interceptors>
                <interceptor-stack name="migrationStack">
                    <interceptor-ref name="timer"/>
                    <interceptor-ref name="logger"/>
                    <interceptor-ref name="chain"/>
                    <interceptor-ref name="static-params"/>
                    <interceptor-ref name="prepare"/>
                    <interceptor-ref name="params"/>
                    <interceptor-ref name="workflow"/>
                </interceptor-stack>
            </interceptors>
            <default-interceptor-ref name="migrationStack"/>
        </package>
    </xwork>

Here we can see that a number of the functions previously performed by ActionFactories in WebWork 1.x are now replaced by Interceptors in WebWork2, including the parameters, the chaining, calling prepare(), and the workflow (which was formerly implemented in ActionSupport in WebWork 1.x).

By creating and saving the ActionConfig in the PackageConfig for the "webwork-migration" package, the ActionConfig for the migrated Action is available for future calls, obviating the need to re-parse the old configuration files and making the configuration for the Action available for querying via the configuration API for tools such as the configuration browser.

### Tag Changes

The biggest change is the use of OGNL for accessing object properties. Properties are no longer accessed with a forward slash "/" but with a dot "." Also, rather than using ".." to traverse down the stack, we now use "[n]" where n is some positive number. Lastly, in WebWork 1.x one could access special named objects (the request scope attributes to be exact) by using "@foo", but now special variables are accessed using "#foo". However, it is important to note that "#foo" does NOT access the request attributes. "#foo" is merely a request to another object in the OgnlContext other than the root. See OGNL reference for more details.

Also see JSP Expression Language Comparison with WebWork 1.x for a table of the expression language changes.

#### property tag

The property tag is now only used to print out values from the stack. In WW1, it was also used to set a variable in the scope, and to push properties to the top of the stack. These functions are now performed by the set and push tags.

#### action tag

The action tag does not evaluate the body section any more and does not push the executed action onto the ValueStack. Instead, use the "id" attribute to assign a name to the action and reference it as "#id".

#### Examples

Lets enumerate some examples of differences between code snips using Home and Home.

- New JSP syntax

There are numerous changes in syntax. First of all there are new tags and secondly there is a new expression language. Here's a small example:

Webwork 1

    <ww:property value="a/b">
      <ww:property value="foo" />
    </ww:property>

Webwork 2

    <ww:push value="a.b">
      <ww:property value="foo" />
    </ww:push>

One can note that the "push" tag doesn't just push it pops too at the end of the tag. Surprise! Also note the "." instead of the "/" for traversing object properties.

- List errors posted by an Action
  Webwork 1

      <webwork:if test="hasErrorMessages == true">
        ERROR:<br />
        <font color="red">
          <webwork:iterator value="errorMessages">
            <webwork:property/><br />
          </webwork:iterator>
        </font>
      </webwork:if>

  Webwork 2

      <webwork:if test="hasErrors()">
        ERROR:<br />
        <font color="red">
          <webwork:iterator value="actionErrors">
            <webwork:property/><br />
          </webwork:iterator>
        </font>
      </webwork:if>

## Update your web.xml file

- If you're using Velocity for views, you'll need to make sure you have the following snippet. Specifically note that the <load-on-startup> tag is now required so that the servlet can initialize some important Velocity properties.

      <servlet>
          <servlet-name>velocity</servlet-name>
          <servlet-class>com.opensymphony.webwork.views.velocity.WebWorkVelocityServlet</servlet-class>
          <load-on-startup>1</load-on-startup>
      </servlet>

- Set the property webwork.velocity.configfile in your _webwork.properties_. For example:

      webwork.velocity.configfile=velocity.properties

WebWork will use this file to initialize the Velocity engine. The search path for the file is:

1. context root (web root)
2. WEB-INF/
3. classpath

- Additional Steps:

1. If you used the <ww:action taglib in 1.3... you used to refernece the java Action classname. In 2.x this reference is now the action name not the class. you will need to change all your old references in your view.

### ResultException doesn't exist anymore

It might be possible to copy WW1's ResultException, and write an Interceptor that catches the ResultExceptions and add the result of getMessage() to the actionErrors of the
executed Action and return ResultException.getResult().

Maybe it would be possible to include ResultException in WW2 too to make migration easier?!

### DateFormatter doesn't exist anymore

It can be replaced by directly using java.text.DateFormat

### addError(String, String) in webwork.action.ActionSupport has been removed

The new method to use is addFieldError(String, String).

### addErrorMessage(String) in webwork.action.ActionSupport has been removed

The new method is now addActionError(String).

### webwork.util.ValueStack has been removed

The ValueStack is com.opensymphony.xwork.util.OgnlValueStack

The old methods pushValue and popValue are renamed to simply push and
pop.

An instance of the ValueStack can be obtained by using ActionContext.getContext().getValueStack instead of the old ValueStack.getStack().

### *Aware-Interfaces have been removed

Instead of implementing ServletRequestAware etc the
[Servlet]ActionContext.getXXX-methods can be used to obtain application-map, request, response etc.

### CommandDriven interface removed

The CommandDriven interface is removed. It is not neccesary to implement a special interface when working with commands anymore. Use the method attribute in your action-Element in xwork.xml to tell xwork which method to invoke on your action.

### isCommand(String) method has been removed

You can see which alias you're accessing by doing this: ActionContext.getContext().getActionInvocation().getProxy().getActionName()