struts-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Sami Dalouche (JIRA)" <>
Subject [jira] Created: (WW-2826) Make struts2 more component-friendly
Date Sun, 05 Oct 2008 20:12:37 GMT
Make struts2 more component-friendly

                 Key: WW-2826
             Project: Struts 2
          Issue Type: New Feature
    Affects Versions: 2.1.2
            Reporter: Sami Dalouche

Contrary to component-oriented frameworks , Struts2 architecture does not try to ignore what
the web is, it just tries to make web programming easier without introducing complex component

However, there are a few things that the component-oriented frameworks got right, and I believe
struts2 should build on its architecture to enable users to create UI components easily. 
These needs arise from the project I am currently working on, and I describe the hacks that
I currently do to 'simulate' components. I also try to envision the features that struts2
could add to make writing components easier. This 'request' should be seen as a meta-feature
request that can be used as a basis for discussing what should be included. Once everybody
agrees, we can create smaller issues that target individual concerns.

So, let's define what a reusable UI component needs to work decently:
- Markup template. (the view)
- Custom CSS for the component
- Custom JavaScript for the component
- Access to helper Java code 
- Access to a given model, expressed as a Java class that has to be pushed on the value stack,
so that it can catch URL/form parameters related to the component
- When the component displays part of a form, the action has to delegate part of the validation
to the component's model, using @VisitorFieldValidator
- a Custom interceptor to set parameters on the action
- Custom properties file for I18N

Frameworks such as tapestry have built-in features for all these concerns. Here is the struts2-way
to achieve the same, with the current feature set :
- Markup/View: Markup template expressed as FTL, either using the Struts2 Component / Taglib
infrastructure, or just plain FTL files that have nothing to do with struts2

- Custom CSS and JavaScript either sourced or included in a specific @component.head  tag.
the developer is responsible for including head in the head section of the page.  The head
macro has to be coded in a way that does not include JS / CSS directly, but first checks if
it hasn't already be included, in case several components transitively depend on a given component
and call it's head as part of the head tag/macro. Also, the tag is responsible to use either
the real .css/.js file, or the one generated by the build system in case there are hooks to
merge CSS and JS files in order to reduce the number of requests.

- Helper java functions have to be registered using a Custom Freemarker Manager. Adding helpers
to the freemarker context is pretty straightforward, but adding the services to the ValueStack
too is a little tricky. You have to make sure you don't  push the same service twice in the
same request, because populateContext() is called several times...

- The component's java model has to be pushed by the action. pretty much like the action's
view has to reference the head tag in the head section. I use a MultipleModelDrivenInterceptor
that works like ModelDrivenInterceptor, except that is pushes a list of objects, instead of
just one.  In case the component adds fields to the form, the action is responsible for adding

- For important parameters and session attributes that are considered globally accessible
on the website, specific interceptors + *Aware interfaces can be used to ease the actions'
job. Things like Users, etc, can be directly injected to the action to avoid boilerplate copy/pasted

- Each component has its own properties file, that is registered in struts.xml as a global
resource bundle.

OK, now, why I think all this stuff is suboptimal :
- There is no common concept in struts that defines what a component is. so all the pieces
are available, but it looks like tricks and hacks that we try to get to work. It would definitely
be less worrying for the developer if struts provided an 'official' way to do it.

- the developer is responsible for adding head to the HTML head section, for creating the
component's Java Model, for pushing it on the value stack, and for delegating validation to
the component. WAO !!! In most cases, if you're not the one who developed the component, you
will forget one of these steps.  

- The developer is responsible for making sure keys are globally unique among components...
Hum... Once again, this gives the impression of a mere hack...
 Pushing some resource bundle using the I18N tag is not an option since it renders the use
of <#nested> useless. For instance, if a component did :
<@s.i18n name="myComponentResourceBundle>
 <@s.text name="" />
 <#nested />
then if the component is called with <@s.text /> code in the <#nested /> section,
the <@s.text would not find its key in the component resource bundle, and would then fail.
Implementing a fallback mechanism that would go down the value stack could partly work, but
would still not fix the duplicate key problem. 

- When we want to do some processing depending on the parameters, and inject some variables
to the current action thanks to a custom interceptor, we don't have access to type converters,
we basically need to do the job by hand (or probably instantiate the type converters, or do
whatever hardcore low level struts or OGNL stuff to achieve the same). So, the only real way
to bind parameters is to use a custom model class that is instantiated and pushed on the value
stack by the action, but then the action has too much stuff to do regarding the component.
See previous section regarding custom java component models.

So, what I think struts could add in order to make writing components more consistent and
easier :
1] A small wiki section that describes the 'preferred' struts approach to creating reusable
components, whatever approach is chosen. Even if the wiki section is considered as a mere
suggestion, it would allow users to realize that it is in fact possible to write components
using struts2, and would certainly help struts2 beginners. 

2] A kind of generic behavior that would allow components (Struts 2 Tag Components) to register
custom CSS and JS code, that would be printed in the default struts2 themes. (<@s.head
/>). In order to select which components are used on a page, I guess that parsing the FTL
would be too weak ? So, it would be acceptable to force the action to declare the list of
the components that are used. Do some people have an idea regarding this ?

3] A way for Struts2 components to declare :
- A method to create the associated java model object, for every request where the component
is used. This model object should be pushed to the value stack automatically.
- the ModelDriven-validation.xml rules that should be included when the component is used.
The main problem I see with that is that is to allow switching validation off, because the
action would probably  want to validate the model for the execute() method, but not the input()
- An interface that an action could implement to receive the populated model (MyModelAware.class),
as well as some callback method that is used to set the model on the implementing action.
A generic interceptor could then use whatever ThreadLocal/request-scoped object to retrieve
all the callback methods that have to be called on the current action, depending on the types
implemented by the action.
- The name of a spring/whatever IoC service that should be registered in the freemarker +
OGNL context, so that FTL views can refer to it
- The name of a .properties file to use for I18N keys lookup. To make this to work, my guess
is that @s.text would need to be completly reworked to be component aware, since both global
keys, and trying eveyr textprovider in the value stack both don't fix the duplicate key problems.
Maybe some experts have a better idea to solve this issue ?

That's it ! (I think) :p

So yeah, still a lot of questions, it's definitely a tough problem, but I really believe it's
worth thinking a little bit about that.
In my project, I am progressively starting to extract abstractions to create components, so
don't hesitate to bring your ideas to complement what I suggested. I would happily share the
code that implements these ideas whenever it is available.

Sami Dalouche

This message is automatically generated by JIRA.
You can reply to this email to add a comment to the issue online.

View raw message