Versions Compared

Key

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

Compare SAF 1 and SAF 2
Wiki Markup


{note}As of December, 2005 the Struts and WebWork teams have agreed to combine their efforts to create Struts Action 2.0. Struts Action 2.0 will be based on WebWork 2.2. Therefore this comparison is less relevant as the two communities cooperate more.{note}

h2. Feature Comparison

{table}
Feature \| SAF Struts1 \| WebWork 1.x \| WebWorkSAF 2.x
*Action classes* \| StrutsSAF 1 requires Action classes to extend an Abstract base class. This shows aA common problem in StrutsSAF 1 ofis programming to abstract classes instead of interfaces. \| ActionAn classesSAF must implement the webwork.2 Action Interface. There are other Interfaces which can be implemented for other services, such as storing error messages, getting localized texts, etc. The ActionSupport class implements many of these Interfaces and can act as a base class. WebWork is all written to Interfaces, which allows for plugging in your own implementations.| An Action must may optionally implement the {{com.opensymphony.xwork.Action}} Interface, with a series of other Interfaces for other services,. likeSAF in2 WebWork 1.x. WebWork2 has its own ActionSupport provides a base ActionSupport class to implement these Interfaces.
*Threading Model* \| StrutsSAF 1 Actions must be thread-safe because there will only be one instance to handle all requests. This strategy places restrictions on what can be done with StrutsSAF 1 Actions as any resources held must be thread-safe or access to them must be synchronized. \| WebWorkSAF 2 Actions are instantiated for each request, so there are no thread-safety issues. In practice, Servlet containers generate many throw-away objects per request, and one more Object does not prove to be a problem for performance or garbage collection. | ditto
*Servlet Dependency* \| StrutsSAF 1 Actions have dependencies on Servlets because they getpass the ServletRequest and ServletResponse (not HttpServletRequest and HttpServletResponse, I'veto been told) when they are executed. This tie to Servlets (although not Http*) is a defacto tiean Action. \| SAF 1 Actions are not tied to a Servlet container,. whichMost isoften anthe unneededServlet dependency.contexts Servletsare mayrepresented beas usedsimple outsideMaps, aallowing Webthe context,Action butto it'sbe nottested ain goodisolation. fitIf for JMSnecessary, for instance. | WebWork SAF 2 Actions arecan notstill tied to the web or any container. WebWork actions CAN choose to access directly access to the request and response from the ActionContext, but it is not required and should be done only when ABSOLUTELY neccessary to avoid tieing code to the Web. | ditto
*Testability* \| ManyA strategiesmajor havehurdle sprung upto around testing StrutsSAF applications,1 but the major hurdle Actions is the fact that Struts Actions are so tightly tied to the web (receiving a Request and Response object). This often leads people to test Struts Actions inside a container, which is both slow and NOT UNIT TESTING. There is a Junit extension : Struts TestCase (http://strutstestcase.sourceforge.net/) | WebWork actionsthe {{execute}} method exposes the Servlet API. A third-party extension, Struts TestCase, offers a set of mock object for SAF 1. \| SAF 2 Actions can be tested by  instantiating yourthe actionAction, setting the properties, and executinginvoking themmethods. |Dependency ditto,Injection butsupport the emphasis on Inversion of Control makes can make testing even simpler, as you can just set a Mock implementation of your services into your Action for testing, instead of having to set up service registries or static singletons
*FormBeans* \| StrutsSAF requires1 theuses usean ofActionForm FormBeansobject forto everycapture forminput, which necessitatingcan eithercreate a lot of extra classes or the use of DynaBeans, which. DynaBeans are reallyoften justused aas workaroundan foralternative theto limitationcreating ofconventional requiringActionForm FormBeansclasses. \| WebWorkSAF 1.x2 allows you to have all of your properties directly accessible on your Action as regular Javabeans properties, including rich Object types which can have their own properties which can be accessed from the web page. WebWorkSAF 2 alsodoes allowssupports the FormBeanActionForm pattern, as discussed in "[WW1:Populate Form Bean and access its value]" | WebWork 2 allows the same features as WebWork 1, but adds along with ModelDriven Actions, which allow you to have a rich Object type or domain object as your form bean, with its properties directly accessible to the web page, rather than accessing them as sub-properties of a property of the Action.
*Expression Language* \| StrutsSAF 1.1 integrates with JSTL, so it uses the JSTL EL. ThisThe EL has basic object graph traversal, but relatively weak collection and indexed property support.  \| WebWork 1.x has its own Expression language which is built for accessing the ValueStack. Collection and indexed property support are basic but good. WebWork can also work with [JSTL] | WebWork uses [Ognl]SAF 2 uses OGNL which is a VERY powerful expression language, with additions for accessing the value stack. Ognl supports very powerful collection and indexed property support. Ognl also supports powerful features like projections (calling the same method on each member of a collection and building a new collection of the results), selections (filtering a collection with a selectorflexible expression tolanguage return a subset), list construction, and lambda expressions (simple functions which can be reused). Ognl also allows access to static methods, static fields, and constructors of classes. WebWork2 may also use JSTL as mentioned in [WW1:Using JSTL seamlessly with WebWork]SAF 2 can also use JSTL 
*Binding values into views* \| SAF Struts1 uses the standard JSP mechanism for binding objects into the page context for access,. which\| tightly couples your view to the form beans being rendered | WebWork SAF 2 sets up a ValueStack which the WebWork taglibs access to dynamically find values very flexibly without tightly coupling your view to the types it is rendering. This strategy allows youreuse toof reuse views across a range of types which have the same properties. | ditto
*Type Conversion* \| StrutsSAF 1 FormBeansActionForm properties are usually all Strings. SAF Struts1 uses Commons-Beanutils for type conversion. Converters are per-class, and not configurable per instance. Getting a meaningful type conversion error out and displaying it to the user can be difficult. | WebWork 1.x uses PropertyEditors for type conversion. PropertyEditors are per type and not settable per Action, but field error messages are added to the field error map in the Action to be automatically displayed to the user with the field. | WebWork2 uses Ognl  \| SAF 2 uses OGNL for type conversion with added converters provided for all basic types. Type converters default to these converters, but type conversion can be specified per field per class. Type conversion errors also have a default error message but can be set per field per class using the localization mechanism in WW2 and will be set into the field error messages of the Action.
*Modular Before & After ProcessingValidation* \| ClassSAF hierarchies1 ofsupports basemanual Actionsvalidation mustvia be built up to do processing before and after delegating to the Action classes, which can lead deep class hierarchies and limitations duea {{validate}} method on the ActionForm, or through an extension to the inability to have multiple inheritance _[WW:Comparison to Struts#1]_ | Class hierarchies | WebWork 2 allows you to modularize before and after processing in Interceptors. Interceptors can be applied dynamically via the configuration without any coupling between the Action classes and the Interceptors. 
*Validation* | Struts calls validate() on the FormBean. Struts users often use Commons Validation for validation. I don't know a lot about this, so I'll put some questions here: \\ \\ Because FormBean properties are usually Strings, some types of validations must either be duplicated (checking type conversion) or cannot be done? \\ \\ Can Commons Validation Commons Validator. Classes can have different validation contexts for the same class? (I've been told yes, so that's a good thing) \\ \\ Can Commons Validation but cannot chain to validations on sub-objects, using the validations defined for that object properties class? | WebWork1.x calls the validate() method on Actions, which can either do programmatic validations or call an outside validation framework (this is apparently the same as Struts) | WebWork can use the validate() method of WebWork and Struts and / or use the [Validation] framework, which is activated using an XWork Interceptor. \| SAF 2 supports manual validation via the {{validate}} method and the XWork [Validation] framework. The Xwork Validation Framework allows you to define validations in an XML format with default validations for a class and custom validations added for different validation contexts. The Xwork Validation Framework is enabled via an Interceptor and is therefore completely decoupled from your Action class. The Xwork Validation Framework also allows you to chain the validation process down supports chaining validation into sub-properties using the VisitorFieldValidator which will use the validations defined for the properties class type and the validation context.
*Control Of Action Execution* \| AsSAF far1 assupports Iseparate know Struts sets up the Action object for you, and you have very little control over the order of operations. To change them I think (?) you need to write your own Servlet to handle dispatching as you want | The ActionFactory chain controls the order in which an Action is constructed and initialised, but this requires writing a class | The interceptor stacks in WebWork 2 are hugely powerful in this regard. All aspects of Action setup have been moved into Interceptor implementations (ie setting paramters from the web, validation etc), so you can control Request Processors (lifecycles) for each module, but all the Actions in the module share he same lifecycle. \| SAF 2 supports creating different lifecycles on a per actionAction basis thevia order in which they are performed. For example you might want your IOC framework to setup the action before the parameters are set from the request or vice versa - you can thusly control this on a per package or per action basis with interceptor stacks. 
{table}

h2. References

* http://www.mail-archive.com/opensymphony-webwork@lists.sourceforge.net/msg00995.html - compares Struts development to WebWork 1.x development from the point of view of a Stuts developer who switched to WebWork
* http://www.mail-archive.com/opensymphony-webwork@lists.sourceforge.net/msg04700.html - Kind of the first draft of this comparison

h2. Footnotes
# {anchor:1} Some Stuts users have built the beginnings of an Interceptor framework for Struts (http://struts.sourceforge.net/saif/). It currently has some serious limitations (no "around" processing, just before and after) and is not part of the main Struts projectInterceptor Stacks.  
{table}