You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by Joe Germuska <Jo...@Germuska.com> on 2005/08/31 22:01:11 UTC

Spring and XWork in Ti (was: Spring and Chain (was Struts Ti doubt))

So, I really do have work I should be doing, but I couldn't help 
looking around XWork a little bit, and I'm just wondering why Ti 
needs to use both it and Spring anyway?

What are the various services offered by each that aren't offered by the other?

Joe


At 2:44 PM -0500 8/31/05, Joe Germuska wrote:
>I don't know anything about how XWork will handle message resources, 
>but what I'm talking about is all internal to Struts anyway, so I'm 
>not sure that the user needs to be concerned; this is more about an 
>alternative to all the LocalStrings.properties files which Struts 
>classes currently have to bootstrap themselves.
>
>Until I see it, I won't argue very hard for using Spring as the 
>message resolver, but I am finding it handy inside my own 
>applications.  Are there any places in Struts Ti where XWork's 
>message facilities are being used?


-- 
Joe Germuska            
Joe@Germuska.com  
http://blog.germuska.com    
"Narrow minds are weapons made for mass destruction"  -The Ex

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Don Brown <mr...@twdata.org>.
At this stage in the project, we are exploring problems and solutions.  It can 
be misleading to follow the dev discussion thinking this is what the user will 
need to know and understand in order to use the project.  Each of the components 
discussed here are solutions to problems.  What Ti is trying to determine is 
what problems it will tackle and what components already provide solutions.

In the end, I envision the average Struts developer not knowing or caring about 
90% of this stuff.  They will write Controller classes, annotated with tags that 
request validation, views, etc., then Ti will take care of it from there.  My 
goal is for the user to not even know they are using XWork, just that when they 
add the @ti.action annotation, they can call that action from a URL.  If they 
want validation, they add a @ti.validationRequired tag.  They shouldn't know or 
care if it is commons-validator under the covers that does the work or XWork 
validations.

This level of user abstraction, I feel, hasn't been a priority for many projects 
and causes confusion.  I'm tired of the confusion caused by Struts apps being a 
mix of Tiles, commons-validator, Struts, Beanutils, etc., and those are just the 
out-of-the-box components Struts ships with.  Some projects like Tapestry solve 
this by rolling their own IoC, HTML template language, component model, etc., to 
present a unified face to the developer.  I'm hoping to also provide a simple, 
unified framework to the developer, but take advantage of all the hard work 
folks have put into projects like Spring, WebWork, Beehive, etc. under the covers.

This may not be a reachable goal, but I'm hoping we can give it a shot.

Don

netsql wrote:
> As MF says: "Comprehensiveness is the enemy of comprehensibility".
> 
> To that end, if there is a way to have one, but not both, it's a plus.
> 
> Spring + CoR + WebWork + XYZ... that looks scary (and still not 
> defulting to "Ajax").
> 
> Don, If you like IoC, lets start w/ HiveMind (or whatever IoC + iBatis 
> DAO) and ignore CoR, and build clean and build for Ajax example of the 
> bat (the 2 Ajax libs that MC talks about, and then rig Faclets or 
> whatever else later, that would give us a sweet spot).
> 
> It has to be teachable at the end.
> 
> .V
> 
> 
> Ted Husted wrote:
> 
>> My only point would be that these tools seem close enough that we
>> should be able to extend one to fill the role of the other.
>>
>> -- 
> 
> 
> Broadband interface (RIA) + mail box safety = Roomity.com
> <http://roomity.com/demo.jsp>
> *Your* clubs, no sign up to read, ad supported; try broadband internet.
> 
> cell: 917 825 3035 in DFW
> email: netsql at roomity.com
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> For additional commands, e-mail: dev-help@struts.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by netsql <ne...@roomity.com>.
As MF says: "Comprehensiveness is the enemy of comprehensibility".

To that end, if there is a way to have one, but not both, it's a plus.

Spring + CoR + WebWork + XYZ... that looks scary (and still not 
defulting to "Ajax").

Don, If you like IoC, lets start w/ HiveMind (or whatever IoC + iBatis 
DAO) and ignore CoR, and build clean and build for Ajax example of the 
bat (the 2 Ajax libs that MC talks about, and then rig Faclets or 
whatever else later, that would give us a sweet spot).

It has to be teachable at the end.

.V


Ted Husted wrote:
> My only point would be that these tools seem close enough that we
> should be able to extend one to fill the role of the other.
> 
>-- 

Broadband interface (RIA) + mail box safety = Roomity.com
<http://roomity.com/demo.jsp>
*Your* clubs, no sign up to read, ad supported; try broadband internet.

cell: 917 825 3035 in DFW
email: netsql at roomity.com


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Ted Husted <te...@gmail.com>.
Well, that is pretty cool. But, using Chain, I wouldn't use a filter. 

I'd define two commands, one to start the timer and one to stop the
timer. The timer would go into the context, which is thread-safe.

Then wherever we wanted to use the timer commands, we'd turn the
command into a chain (if it already wasn't).

So, if we had something like 

  <object id="issue_select" parent="BaseSelect">
		<property name="Input">
			<list>
				<value>issue_key</value>
			</list>
		</property>
		<property name="Output">
			<list>
				<value>issue_code</value>
				<value>issue_type</value>
			</list>
		</property>
	</object>

we'd just make turn it into a chain 

  <object id="issue_select" parent="BaseChain">
		<property name="AddCommands">
			<list>
				<ref object="timer_stop" />
				<ref object="issue_select_core" />
				<ref object="timer_start" />
			</list>
		</property>
  </object>

  <object id="issue_select_core" parent="BaseSelect">
		<property name=input">
			<list>
				<value>issue_key</value>
			</list>
		</property>
		<property name="output">
			<list>
				<value>issue_code</value>
				<value>issue_type</value>
			</list>
		</property>
	</object>

If we wanted to time everything, we'd add them to the aforementioned
pre/post chains instead.

If such things were happening all the time, we could also add pre/post
chains to the base command processing. If the before and/or after
properties were present on the command, the processor could create a
dynamic chain to include them.

  <object id="issue_select" parent="BaseSelect">
		<property name="Input">
			<list>
				<value>issue_key</value>
			</list>
		</property>
		<property name="Output">
			<list>
				<value>issue_code</value>
				<value>issue_type</value>
			</list>
		</property>
		<property name="AddBefore">
			<list>
			<list>
				<ref object="timer_start" />
			</list>
		</property>
		<property name="AddAfter">
			<list>
			<list>
				<ref object="timer_stop" />
			</list>
		</property>
	</object>

So, where WebWork added chain processing to the interceptor, we could
add interception to the chain processing. :)

My only point would be that these tools seem close enough that we
should be able to extend one to fill the role of the other.

Of course, that might be something better decided once there is a
working framework to try stuff with. :)

-T.

On 9/1/05, Don Brown <mr...@twdata.org> wrote:
> Perhaps an example would help convey what I'm trying to say:
> 
> Take a simple case where you want to processing time and log it to a file.  As a
> XWork interceptor, it would look like this:
> 
>    long startTime = System.currentTimeMillis();
>    String result = invocation.invoke();
>    long executionTime = System.currentTimeMillis() - startTime;
>    log.info("Execution time: "+executionTime+" ms");
> 
> Here, we define a method variable, startTime, before the rest of the execution,
> then need to access it after the execution is done.
> 
> If we wanted to write this as a Filter in commons-chain, we couldn't without
> making startTime a class level variable, but then the command would no longer be
> thread-safe.
> 
> Ah, but you might suggest we write that as a chain since a chain has explicit
> control over executing its children.  But then, we'd have to define the rest of
> the commands within that chain and if you have multiple commands like this timer
> command, they too would have to be chains:
>    process-chain
>      timer-chain
>        fooCommand
>        otherAroundCommand
>          barCommand
>      ....
> 
> This obviously has the disadvantage of deep nesting losing some of the
> readability of a simple process chain.
> 
> Therefore, my point is an interceptor chain is better suited to a scalable,
> linear process flow, while chain is better for decision points.  And neither,
> I'd argue, is well suited for a robust, configurable workflow, and this surely
> we can agree we are seeing with commons-chain in Struts Classic.
> 
> Don
> 
> BTW, I'm really enjoying this discussion and have missed these on this list.
> 
> Ted Husted wrote:
> > On 9/1/05, Don Brown <mr...@twdata.org> wrote:
> >
> >>In that case, I find interceptors more practical, as they allow
> >>you to have code before and after processing that uses method variables.  With
> >>Chain, you have to use a Filter and even then, there is no way to share
> >>variables between the two blocks of code without instance variables which has
> >>its own problems.
> >
> >
> > First, you're doing the work, Don, and so you're welcome to make the
> > decisions :)
> >
> > Though, I don't understand is why you'd want to be restricted to two
> > blocks of code :)
> >
> > With Chain, any number of blocks of code, be they commands or chains,
> > in any combination, can be the object of the request processing.
> >
> > In OverDrive/Nexus, we do find having interceptors that surround each
> > request useful. It's not hard to define "pre" and "post" chains, and
> > then at runtime create a third chain to execute them all.
> >
> >               public void ExecuteView (IRequestContext context)
> >               {
> >                       IRequestCommand command = VerifyRequest (context);
> >                       if (context.IsNominal)
> >                       {
> >                               IChain chain = new Chain ();
> >                               if (_PreOp!=null) chain.AddCommand (_PreOp);
> >                               chain.AddCommand (command);
> >                               if (_PostOp!=null) chain.AddCommand (_PostOp);
> >                               try
> >                               {
> >                                       chain.Execute (context);
> >                               }
> >                               catch (Exception e)
> >                               {
> >                                       context.Fault = e;
> >                               }
> >                       }
> >               }
> >
> > http://svn.apache.org/viewcvs.cgi/struts/sandbox/trunk/overdrive/Nexus/Extras/Spring/Catalog.cs?view=markup
> >
> > The PreOp and PostOp chains are defined in the configuration, along
> > with everything else.
> >
> > But, we're not trying to solve the problems of navigational workflows,
> > only the problem of processing business use cases and interacting with
> > a presentation layer
> >
> > -Ted.,
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> > For additional commands, e-mail: dev-help@struts.apache.org
> >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> For additional commands, e-mail: dev-help@struts.apache.org
> 
> 


-- 
HTH, Ted.
http://www.husted.com/poe/

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


OT: Re: Spring and XWork in Ti

Posted by netsql <ne...@roomity.com>.
Ted Husted wrote:
.
> 
> Many other .NET applications   ...

Here is one C# ex:

http://www.castleproject.org/movies/CoR_Overview_Smallmod.htm


-- 
thx,
.V

Broadband interface (RIA) + mail box safety = Roomity.com
<http://roomity.com/demo.jsp>
*Your* clubs, no sign up to read, ad supported; try broadband internet.

cell: 917 825 3035 in DFW
email: netsql at roomity.com


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Ted Husted <te...@gmail.com>.
On 9/2/05, Don Brown <mr...@twdata.org> wrote:
> Ted Husted wrote:
> > Well, in the spirit of discussion ...
> >
> > An important consideration is where to put the composition. We haven't
> > figured out how to use the Spring.Web wizards yet, so for our .NET
> > apps we've been decomposing the "pages" or "dialogs" into User
> > Controls. The actual ASPX page then becomes a list of controls that
> > the workflow might use.
> 
> That's a very interesting approach, so in effect, your page behind becomes your
> "Controller" containing multiple page actions.  I wonder how/if that would
> translate to JSF.  Reminds me of the folks that are doing pure client-side, one
>   url apps, using javascript to handle page navigation.

Yes. I expect that the approach would port, given the similarities
between the platforms.

Many other .NET applications do the same sort of thing, but typically
use a "placeholder" control in the page to swap other controls in and
out. Swapping seems to work well enough, but code-behind logic can get
hoary, especiallly when people try to use one page to serve the entire
application. The placeholder approach also makes the application
harder to "discover" for someone just wandering through the code.

Under the container page approach, you can look at the page and see
what User Controls are involved. It's also very easy to pass values,
since the components are all live. We just have to be careful to not
let the list components save large lists, which encumbers the page
state.

When we do need to jump between pages, Spring.WEB has a very nice
"ActionForward" like component.

* http://opensource2.atlassian.com/confluence/spring/display/NET/Result+mapping

For the business logic, we inject a "ViewHellper" into the page that
encapsulates the Context and Command into a single facade. Typical
calls look like

public void Open()
{
 if (IsPostBack) return;
 IViewHelper helper = ExecuteBind(App.ROUTING_FIND);
 if (!helper.IsNominal()) Page_Error = helper;
}

Line 2 executes the command named "routing_find", and then binds the
result values to the UI controls.

Line 3 asks the helper if all went well, and if not, hands the helper
to the Page_Error property. This "property" actually fires an event
handler, which passes the helper to to the containing page, which
displays the message.

Any manner of error could be displayed  here, including system errors
coming back from the database.

----

private void find_Click(object sender, EventArgs e)
{
 if (Click == null) return;
 IViewHelper helper = Read(App.ROUTING_FIND);
 if (helper.IsNominal())
  Click(this, new ViewArgs(helper));
}

Here, line 2 reads values input by the user. If all goes well, line 3
throws a Click event to be caught by the containing page.

----

protected IViewHelper save_Changes()
{
 IViewHelper helper = ReadExecute(App.FACILITY_SAVE);
 if (helper.IsNominal()) Page_Reset();
 else Page_Error = helper;
 return helper;
}

Line 1 reads values input by the user, and then executes the
"facility_save" command. Depending on whether everything worked, the
second statement either resets the UI controls, or displays any
messages. The helper is returned to the caller, in case further
processing is needed.

----

In case anyone is interested, I posted a copy of our internal User
Control RFC here:

* http://husted.wush.net/docs/display/NEO/RFC+-+User+Controls

-Ted.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Don Brown <mr...@twdata.org>.
Ted Husted wrote:
> Well, in the spirit of discussion ...
> 
> An important consideration is where to put the composition. We haven't
> figured out how to use the Spring.Web wizards yet, so for our .NET
> apps we've been decomposing the "pages" or "dialogs" into User
> Controls. The actual ASPX page then becomes a list of controls that
> the workflow might use.

That's a very interesting approach, so in effect, your page behind becomes your 
"Controller" containing multiple page actions.  I wonder how/if that would 
translate to JSF.  Reminds me of the folks that are doing pure client-side, one 
  url apps, using javascript to handle page navigation.

Don


> 
> <HTML>
> <body>
> <spring:Content contentPlaceholderId="cphMain" id="cphMainContent"
> runat="server">
> 
> <wqd:RoutingMerger id="routing_merger" Runat="server"></wqd:RoutingMerger>
> 
> <wqd:RoutingEditor id="routing_editor" Runat="server"
> OnQuit="routing_editor_Quit"
> OnSave="routing_editor_Save"></wqd:RoutingEditor>
> 
> <wqd:FacilityEditor id="facility_editor" Runat="server"
> OnQuit="facility_editor_Quit"
> OnSave="facility_editor_Save"></wqd:FacilityEditor>
> 
> <wqd:FacilityLister id="facility_lister" runat="server"
> OnAdd="facility_lister_Add"
> OnClick="facility_lister_Click"></wqd:FacilityLister>
> 
> <wqd:FacilityFinder id="facility_finder" Runat="server"
> OnClick="facility_finder_Click"></wqd:FacilityFinder>
> 
> </spring:Content>
> </body>
> </HTML>
> 
> Running from the bottom, this particular page displays a "Facilty
> Finder". Once the user enters some search criteria, the result is
> displayed by the "Facility Lister". Here they can branch to a Facility
> Editor, to add or edit a Facility, or go on to the Routing Editor. The
> Routing Editor collects details for a "Routing Sliip", which can then
> be merged into Word document, if the user choose.
> 
> All the business and presentation logic for each step is encapsulated
> in the individual controls. We then use the page's code-behind to
> shepard the navigation. The code-behind makes the controls visible or
> invisible as needed, reacts to the registered events, and passes
> values between controls as needed. Each control has properties to
> represent the input and output values. Since the controls are external
> to the page, we can reuse the controls in other workflows.
> 
> Here's the handler that grabs the search criteria and passes it to the
> Facility Lister:
> 
> 		protected void facility_finder_Click(object sender, EventArgs e)
> 		{
> 			ViewArgs v = e as ViewArgs;
> 			facility_lister.list_Criteria = v.Helper.Criteria;
> 			facility_lister.Open();
> 			facility_lister.Visible = true;
> 		}
> 
> The nice part is that we can focus on one thing at a time. If there's
> an issue with a control, we can edit just the control. If there's an
> issue with the navigation, we can focus on that, without all the
> control code clutter.
> 
> To run the actual business logic, each control can access the object
> catalog, which contains our command Helpers and other goodies. The
> code-behinds for the controls collect the appropriate values, invoke
> the business commands, and call an event handler when they are done.
> 
> The icing on the cake is that we have figured out how to use the
> Spring.Web master pages. So we don't need to include any chrome on the
> workflow pages. Aside from registering the tags, all we need is what's
> above. All the headers, footers, and menu stuff is in other "Tiles.".
> 
> -Ted.
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> For additional commands, e-mail: dev-help@struts.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Ted Husted <te...@gmail.com>.
On 9/1/05, Joe Germuska <Jo...@germuska.com> wrote:
> but that XML is not a very nice way to define everything that needs
> to happen, and object-level composition is also likely to be awkward
> for some of these kinds of things.  

Well, in the spirit of discussion ...

An important consideration is where to put the composition. We haven't
figured out how to use the Spring.Web wizards yet, so for our .NET
apps we've been decomposing the "pages" or "dialogs" into User
Controls. The actual ASPX page then becomes a list of controls that
the workflow might use.

<HTML>
<body>
<spring:Content contentPlaceholderId="cphMain" id="cphMainContent"
runat="server">

<wqd:RoutingMerger id="routing_merger" Runat="server"></wqd:RoutingMerger>

<wqd:RoutingEditor id="routing_editor" Runat="server"
OnQuit="routing_editor_Quit"
OnSave="routing_editor_Save"></wqd:RoutingEditor>

<wqd:FacilityEditor id="facility_editor" Runat="server"
OnQuit="facility_editor_Quit"
OnSave="facility_editor_Save"></wqd:FacilityEditor>

<wqd:FacilityLister id="facility_lister" runat="server"
OnAdd="facility_lister_Add"
OnClick="facility_lister_Click"></wqd:FacilityLister>

<wqd:FacilityFinder id="facility_finder" Runat="server"
OnClick="facility_finder_Click"></wqd:FacilityFinder>

</spring:Content>
</body>
</HTML>

Running from the bottom, this particular page displays a "Facilty
Finder". Once the user enters some search criteria, the result is
displayed by the "Facility Lister". Here they can branch to a Facility
Editor, to add or edit a Facility, or go on to the Routing Editor. The
Routing Editor collects details for a "Routing Sliip", which can then
be merged into Word document, if the user choose.

All the business and presentation logic for each step is encapsulated
in the individual controls. We then use the page's code-behind to
shepard the navigation. The code-behind makes the controls visible or
invisible as needed, reacts to the registered events, and passes
values between controls as needed. Each control has properties to
represent the input and output values. Since the controls are external
to the page, we can reuse the controls in other workflows.

Here's the handler that grabs the search criteria and passes it to the
Facility Lister:

		protected void facility_finder_Click(object sender, EventArgs e)
		{
			ViewArgs v = e as ViewArgs;
			facility_lister.list_Criteria = v.Helper.Criteria;
			facility_lister.Open();
			facility_lister.Visible = true;
		}

The nice part is that we can focus on one thing at a time. If there's
an issue with a control, we can edit just the control. If there's an
issue with the navigation, we can focus on that, without all the
control code clutter.

To run the actual business logic, each control can access the object
catalog, which contains our command Helpers and other goodies. The
code-behinds for the controls collect the appropriate values, invoke
the business commands, and call an event handler when they are done.

The icing on the cake is that we have figured out how to use the
Spring.Web master pages. So we don't need to include any chrome on the
workflow pages. Aside from registering the tags, all we need is what's
above. All the headers, footers, and menu stuff is in other "Tiles.".

-Ted.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Joe Germuska <Jo...@Germuska.com>.
At 12:41 PM -0700 9/1/05, Don Brown wrote:
>Hmm...well there are three main issues we are discussing here, 
>although you mention at the end they do have some overlap:
>
>1. Framework-level request processing
>2. Action-level processing
>3. Application-level page flow/workflow
>
>When was referring to commons-chain being a poor match for workflow 
>I was primarily talking about #1.  Examples of this include how 
>Struts Classic commands have all sorts of ugly logic in them to skip 
>themselves if an object isn't found in the context.  This seems 
>fine...

I don't really think it seems fine, but I don't think this is endemic 
to commons-chain; I think it's just a naive implementation of the 
original translation of the RequestProcessor to commons-chain.  (No 
offense meant by the term "naive".)

That said, while I've had some ideas about how to do it better, I'm 
not sold on any of them, so maybe commons-chain still doesn't deal 
with this extremely well.   And as I write this, I realize that your 
point, Don, is that one could probably do it all with commons-chain, 
but that XML is not a very nice way to define everything that needs 
to happen, and object-level composition is also likely to be awkward 
for some of these kinds of things.  For example, a conditional lookup 
command which dealt with 2..n possible branches would be difficult to 
configure simply by setting bean properties upon a generic "branch 
command".  (At least, I think this is your point, or part of it...)

Still, Struts 1.3 could have a cleaner default RP chain, and I feel 
that it exposes the RP process adequately for customization, but it 
seems clear that it will still be at least a "journeyman" level task 
for someone to make modifications to the chain, particularly given 
how tightly coupled local modifications are to the Struts base 
process.  (It would be nice to have some "advice" like way to 
decorate the chain, as with Maven preGoal and postGoal, but I haven't 
thought of a way I'd propose to do that without substantially 
reorganizing commons-chain's basic model.  For a while Bob McWhirter 
was distributing werkz, which I think is the core of Maven 1.x's 
process, but that seems to have disappeared from werken.com or 
codehaus.org.)

Joe

-- 
Joe Germuska            
Joe@Germuska.com  
http://blog.germuska.com    
"Narrow minds are weapons made for mass destruction"  -The Ex

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Don Brown <mr...@twdata.org>.
Hmm...well there are three main issues we are discussing here, although you 
mention at the end they do have some overlap:

1. Framework-level request processing
2. Action-level processing
3. Application-level page flow/workflow

When was referring to commons-chain being a poor match for workflow I was 
primarily talking about #1.  Examples of this include how Struts Classic 
commands have all sorts of ugly logic in them to skip themselves if an object 
isn't found in the context.  This seems fine until you step back and realize it 
is very hard to see the overall process flow without digging into the source 
code of each command.  I'm not sure I have a solution to this problem so at the 
moment, Ti uses commons-chain so that at least a user could override a step or 
two in the process as needed.

Action-level processing is what I would consider basic services available for 
action invocation and view processing, including form bean creation, population, 
validation, logging, etc.  Interceptors is a good design, I feel, for this 
problem because you usually want a short, linear process/chain that may differ 
per action, but generally be the same.  There is no need for branching or states 
here, as this could be considered a subset of Aspect-Oriented Programming.

Application-level page flow targets a different audience and presumably harder 
problems including multi-request flows, and I would classify them as solving the 
problem of what action or actions should be invoked per request.  I would 
include action and view processing in this flow.  Solutions include:
1. Beehive's Page Flow
2. Spring's Web Flow
3. Cocoon's Control Flow

What I like about Beehive's Page Flow is it is annotation driven, and supports 
advanced features like shared flows and inherited flows.  Spring's Web Flow is 
new to me, so I can't comment much other than it seems clean but difficult to 
follow without a visualization tool.  And for Cocoon and continuations in 
general, I still think they are a great solution since the workflow is 
implemented in code (Javascript, Java, Ruby, whatever), and furthermore, the 
workflow is in one, easy to read location, generally one method/function.

I suppose it could be argued that all these could share the same tool, but, IMO, 
each have their own requirements and deserve a specialized tool suited for their 
use cases.  Commons-chain could, perhaps, be used for these three types of 
processing, but I fear it would be verbose and cumbersome.

Don



Craig McClanahan wrote:
> On 9/1/05, Don Brown <mr...@twdata.org> wrote:
> 
> Therefore, my point is an interceptor chain is better suited to a scalable,
> 
>>linear process flow, while chain is better for decision points. And 
>>neither,
>>I'd argue, is well suited for a robust, configurable workflow, and this 
>>surely
>>we can agree we are seeing with commons-chain in Struts Classic.
> 
> 
> 
> I generally agree with this, and the other points Don has made in this 
> thread ... and would suggest (sorry Don :-) that the same issue happens with 
> continuations based architectures like Cocoon Webflow and Struts Flow. None 
> of these approaches seem to deal with conditional branches in workflows very 
> well.
> 
> This is one of the reasons that I was initially enamored with Spring 
> WebFlow's approach, which defines the processing logic as a series of 
> states, linked by transitions. States can be action states (like calling 
> Action.execute() in a Struts app) or view states (display a page, receive 
> the subsequent form submit. All states return an outcome that can be used to 
> drive the transition, so you can do branches very easily. Or, you can glue 
> together any number of action states in sequence to get the fine grained 
> sequential functionality that a chain provides.
> 
> In Shale, this idea is encapsulated as a "dialog", which leverages the fact 
> that JSF action methods already returned a String outcome (so that it fit 
> naturally into the state transition model) -- I just added the idea of an 
> action state represented as an expression that called some arbitrary method 
> that also returned a String. This lets you do things like representing an 
> entire workflow in an easy to understand configuration (or, equivalently, in 
> a UML state diagram):
> 
> <!-- Log On / Create Profile Dialog -->
> <dialog name="Log On"
> start="Check Cookie">
> 
> <action name="Check Cookie"
> method="#{profile$logon.check}">
> <transition outcome="authenticated"
> target="Exit"/>
> <transition outcome="unauthenticated"
> target="Logon Form"/>
> </action>
> 
> <view name="Logon Form"
> viewId="/profile/logon.jsp">
> <transition outcome="authenticated"
> target="Exit"/>
> <transition outcome="create"
> target="Create Profile"/>
> </view>
> 
> <subdialog name="Create Profile"
> dialogName="Edit Profile">
> <transition outcome="success"
> target="Exit"/>
> </subdialog>
> 
> <end name="Exit"
> viewId="/usecases.jsp"/>
> 
> </dialog>
> 
> Although the dialog facility is primary focused around multi-request 
> workflows, you can leverage the same concepts for fine grained flows within 
> a particular request.
> 
> Craig
> 
> 
> 
> Don
> 
>>BTW, I'm really enjoying this discussion and have missed these on this 
>>list.
>>
>>Ted Husted wrote:
>>
>>>On 9/1/05, Don Brown <mr...@twdata.org> wrote:
>>>
>>>
>>>>In that case, I find interceptors more practical, as they allow
>>>>you to have code before and after processing that uses method variables. 
>>
>>With
>>
>>>>Chain, you have to use a Filter and even then, there is no way to share
>>>>variables between the two blocks of code without instance variables 
>>
>>which has
>>
>>>>its own problems.
>>>
>>>
>>>First, you're doing the work, Don, and so you're welcome to make the
>>>decisions :)
>>>
>>>Though, I don't understand is why you'd want to be restricted to two
>>>blocks of code :)
>>>
>>>With Chain, any number of blocks of code, be they commands or chains,
>>>in any combination, can be the object of the request processing.
>>>
>>>In OverDrive/Nexus, we do find having interceptors that surround each
>>>request useful. It's not hard to define "pre" and "post" chains, and
>>>then at runtime create a third chain to execute them all.
>>>
>>>public void ExecuteView (IRequestContext context)
>>>{
>>>IRequestCommand command = VerifyRequest (context);
>>>if (context.IsNominal)
>>>{
>>>IChain chain = new Chain ();
>>>if (_PreOp!=null) chain.AddCommand (_PreOp);
>>>chain.AddCommand (command);
>>>if (_PostOp!=null) chain.AddCommand (_PostOp);
>>>try
>>>{
>>>chain.Execute (context);
>>>}
>>>catch (Exception e)
>>>{
>>>context.Fault = e;
>>>}
>>>}
>>>}
>>>
>>>
>>
>>http://svn.apache.org/viewcvs.cgi/struts/sandbox/trunk/overdrive/Nexus/Extras/Spring/Catalog.cs?view=markup
>>
>>>The PreOp and PostOp chains are defined in the configuration, along
>>>with everything else.
>>>
>>>But, we're not trying to solve the problems of navigational workflows,
>>>only the problem of processing business use cases and interacting with
>>>a presentation layer
>>>
>>>-Ted.,
>>>
>>>---------------------------------------------------------------------
>>>To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
>>>For additional commands, e-mail: dev-help@struts.apache.org
>>>
>>
>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
>>For additional commands, e-mail: dev-help@struts.apache.org
>>
>>
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Craig McClanahan <cr...@gmail.com>.
On 9/1/05, Don Brown <mr...@twdata.org> wrote:

Therefore, my point is an interceptor chain is better suited to a scalable,
> linear process flow, while chain is better for decision points. And 
> neither,
> I'd argue, is well suited for a robust, configurable workflow, and this 
> surely
> we can agree we are seeing with commons-chain in Struts Classic.


I generally agree with this, and the other points Don has made in this 
thread ... and would suggest (sorry Don :-) that the same issue happens with 
continuations based architectures like Cocoon Webflow and Struts Flow. None 
of these approaches seem to deal with conditional branches in workflows very 
well.

This is one of the reasons that I was initially enamored with Spring 
WebFlow's approach, which defines the processing logic as a series of 
states, linked by transitions. States can be action states (like calling 
Action.execute() in a Struts app) or view states (display a page, receive 
the subsequent form submit. All states return an outcome that can be used to 
drive the transition, so you can do branches very easily. Or, you can glue 
together any number of action states in sequence to get the fine grained 
sequential functionality that a chain provides.

In Shale, this idea is encapsulated as a "dialog", which leverages the fact 
that JSF action methods already returned a String outcome (so that it fit 
naturally into the state transition model) -- I just added the idea of an 
action state represented as an expression that called some arbitrary method 
that also returned a String. This lets you do things like representing an 
entire workflow in an easy to understand configuration (or, equivalently, in 
a UML state diagram):

<!-- Log On / Create Profile Dialog -->
<dialog name="Log On"
start="Check Cookie">

<action name="Check Cookie"
method="#{profile$logon.check}">
<transition outcome="authenticated"
target="Exit"/>
<transition outcome="unauthenticated"
target="Logon Form"/>
</action>

<view name="Logon Form"
viewId="/profile/logon.jsp">
<transition outcome="authenticated"
target="Exit"/>
<transition outcome="create"
target="Create Profile"/>
</view>

<subdialog name="Create Profile"
dialogName="Edit Profile">
<transition outcome="success"
target="Exit"/>
</subdialog>

<end name="Exit"
viewId="/usecases.jsp"/>

</dialog>

Although the dialog facility is primary focused around multi-request 
workflows, you can leverage the same concepts for fine grained flows within 
a particular request.

Craig



Don
> 
> BTW, I'm really enjoying this discussion and have missed these on this 
> list.
> 
> Ted Husted wrote:
> > On 9/1/05, Don Brown <mr...@twdata.org> wrote:
> >
> >>In that case, I find interceptors more practical, as they allow
> >>you to have code before and after processing that uses method variables. 
> With
> >>Chain, you have to use a Filter and even then, there is no way to share
> >>variables between the two blocks of code without instance variables 
> which has
> >>its own problems.
> >
> >
> > First, you're doing the work, Don, and so you're welcome to make the
> > decisions :)
> >
> > Though, I don't understand is why you'd want to be restricted to two
> > blocks of code :)
> >
> > With Chain, any number of blocks of code, be they commands or chains,
> > in any combination, can be the object of the request processing.
> >
> > In OverDrive/Nexus, we do find having interceptors that surround each
> > request useful. It's not hard to define "pre" and "post" chains, and
> > then at runtime create a third chain to execute them all.
> >
> > public void ExecuteView (IRequestContext context)
> > {
> > IRequestCommand command = VerifyRequest (context);
> > if (context.IsNominal)
> > {
> > IChain chain = new Chain ();
> > if (_PreOp!=null) chain.AddCommand (_PreOp);
> > chain.AddCommand (command);
> > if (_PostOp!=null) chain.AddCommand (_PostOp);
> > try
> > {
> > chain.Execute (context);
> > }
> > catch (Exception e)
> > {
> > context.Fault = e;
> > }
> > }
> > }
> >
> > 
> http://svn.apache.org/viewcvs.cgi/struts/sandbox/trunk/overdrive/Nexus/Extras/Spring/Catalog.cs?view=markup
> >
> > The PreOp and PostOp chains are defined in the configuration, along
> > with everything else.
> >
> > But, we're not trying to solve the problems of navigational workflows,
> > only the problem of processing business use cases and interacting with
> > a presentation layer
> >
> > -Ted.,
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> > For additional commands, e-mail: dev-help@struts.apache.org
> >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> For additional commands, e-mail: dev-help@struts.apache.org
> 
>

Re: Spring and XWork in Ti

Posted by Don Brown <mr...@twdata.org>.
Perhaps an example would help convey what I'm trying to say:

Take a simple case where you want to processing time and log it to a file.  As a 
XWork interceptor, it would look like this:

   long startTime = System.currentTimeMillis();
   String result = invocation.invoke();
   long executionTime = System.currentTimeMillis() - startTime;
   log.info("Execution time: "+executionTime+" ms");

Here, we define a method variable, startTime, before the rest of the execution, 
then need to access it after the execution is done.

If we wanted to write this as a Filter in commons-chain, we couldn't without 
making startTime a class level variable, but then the command would no longer be 
thread-safe.

Ah, but you might suggest we write that as a chain since a chain has explicit 
control over executing its children.  But then, we'd have to define the rest of 
the commands within that chain and if you have multiple commands like this timer 
command, they too would have to be chains:
   process-chain
     timer-chain
       fooCommand
       otherAroundCommand
         barCommand
     ....

This obviously has the disadvantage of deep nesting losing some of the 
readability of a simple process chain.

Therefore, my point is an interceptor chain is better suited to a scalable, 
linear process flow, while chain is better for decision points.  And neither, 
I'd argue, is well suited for a robust, configurable workflow, and this surely 
we can agree we are seeing with commons-chain in Struts Classic.

Don

BTW, I'm really enjoying this discussion and have missed these on this list.

Ted Husted wrote:
> On 9/1/05, Don Brown <mr...@twdata.org> wrote:
> 
>>In that case, I find interceptors more practical, as they allow
>>you to have code before and after processing that uses method variables.  With
>>Chain, you have to use a Filter and even then, there is no way to share
>>variables between the two blocks of code without instance variables which has
>>its own problems.
> 
> 
> First, you're doing the work, Don, and so you're welcome to make the
> decisions :)
> 
> Though, I don't understand is why you'd want to be restricted to two
> blocks of code :)
> 
> With Chain, any number of blocks of code, be they commands or chains,
> in any combination, can be the object of the request processing.
> 
> In OverDrive/Nexus, we do find having interceptors that surround each
> request useful. It's not hard to define "pre" and "post" chains, and
> then at runtime create a third chain to execute them all.
> 
> 		public void ExecuteView (IRequestContext context)
> 		{
> 			IRequestCommand command = VerifyRequest (context);
> 			if (context.IsNominal)
> 			{
> 				IChain chain = new Chain ();
> 				if (_PreOp!=null) chain.AddCommand (_PreOp);
> 				chain.AddCommand (command);
> 				if (_PostOp!=null) chain.AddCommand (_PostOp);
> 				try
> 				{
> 					chain.Execute (context);
> 				}
> 				catch (Exception e)
> 				{
> 					context.Fault = e;
> 				}
> 			}
> 		}
> 
> http://svn.apache.org/viewcvs.cgi/struts/sandbox/trunk/overdrive/Nexus/Extras/Spring/Catalog.cs?view=markup
> 
> The PreOp and PostOp chains are defined in the configuration, along
> with everything else.
> 
> But, we're not trying to solve the problems of navigational workflows,
> only the problem of processing business use cases and interacting with
> a presentation layer
> 
> -Ted.,
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> For additional commands, e-mail: dev-help@struts.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Ted Husted <te...@gmail.com>.
On 9/1/05, Don Brown <mr...@twdata.org> wrote:
>In that case, I find interceptors more practical, as they allow
> you to have code before and after processing that uses method variables.  With
> Chain, you have to use a Filter and even then, there is no way to share
> variables between the two blocks of code without instance variables which has
> its own problems.

First, you're doing the work, Don, and so you're welcome to make the
decisions :)

Though, I don't understand is why you'd want to be restricted to two
blocks of code :)

With Chain, any number of blocks of code, be they commands or chains,
in any combination, can be the object of the request processing.

In OverDrive/Nexus, we do find having interceptors that surround each
request useful. It's not hard to define "pre" and "post" chains, and
then at runtime create a third chain to execute them all.

		public void ExecuteView (IRequestContext context)
		{
			IRequestCommand command = VerifyRequest (context);
			if (context.IsNominal)
			{
				IChain chain = new Chain ();
				if (_PreOp!=null) chain.AddCommand (_PreOp);
				chain.AddCommand (command);
				if (_PostOp!=null) chain.AddCommand (_PostOp);
				try
				{
					chain.Execute (context);
				}
				catch (Exception e)
				{
					context.Fault = e;
				}
			}
		}

http://svn.apache.org/viewcvs.cgi/struts/sandbox/trunk/overdrive/Nexus/Extras/Spring/Catalog.cs?view=markup

The PreOp and PostOp chains are defined in the configuration, along
with everything else.

But, we're not trying to solve the problems of navigational workflows,
only the problem of processing business use cases and interacting with
a presentation layer

-Ted.,

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Don Brown <mr...@twdata.org>.
Joe Germuska wrote:
>> Just as we discovered Chain commands were difficult to use for Struts 
>> users (all the casting for one), Ti users will generally write 
>> interceptors and not chain commands.  Interceptors are more natural, 
>> support around operations better due to easier use local variables, 
>> and provider easier access to the Action they are intercepting with no 
>> casting.
> 
> 
> I'm just wondering when this discovery was made.  I don't recall seeing 
> a lot of discussion about it.  I don't know enough about WebWork 
> interceptors to argue whether they are easier or not, although it seems 
> like if you really want to implement "around" style programming, they 
> would fit better, since the model with which Struts executes per-mapping 
> commands doesn't really give you anything to wrap around.  I guess you 
> can always make a chain with filters; I can't think of a time I ever 
> wanted to apply a solution like that, so it's pretty abstract to me.  I 
> just don't remember there being much discussion about whether commands 
> were easy or hard.

I'm referring to more to how chain worked before we added our own ActionContext, 
and even then, I personally find its "return true or false" unintuitive for 
process flow.  In that case, I find interceptors more practical, as they allow 
you to have code before and after processing that uses method variables.  With 
Chain, you have to use a Filter and even then, there is no way to share 
variables between the two blocks of code without instance variables which has 
its own problems.

That is not to say I don't like chain, but I think it is better suited for 
"chain of responsibility" needs rather than process flow, and when it comes to 
the end user, we should make things as easy and intuitive as possible. 
Interceptors, following the pattern of Servlet filters, does that, IMO.

XWork and WebWork have a ton of examples of interesting uses of interceptors, 
but one in particular is their WorkflowInterceptor, which brings Struts 
Classic-style workflow (populate, validate, if fails, goto input) to Ti/Webwork. 
  What is interesting is this is optional and can be replaced if a different 
workflow suites you better in a very straightforward way (see xwork.xml 
interceptor defs which will be annotations in Ti).

> 
>> In Ti, while we do use chain for general request processing, where I 
>> think it really shines is decision points, something the CoR is built 
>> to solve.  A good example is the chain that creates a form bean.  A 
>> chain is called, and the first command that sees it can create it, 
>> does, then returns "true" as the responsibility has been assumed.  So 
>> in summary, Ti developers will work with chains and some interceptors, 
>> while the average Ti application will only need to know interceptors.
> 
> 
> Ti depends on commons-chain 1.0.  The LookupCommand in that version of 
> commons-chain treats a "true" return value from any called chain as a 
> signal to abort the entire chain processing.  Did Ti reimplement the 
> idea that some commands would ignore the return value from a 
> looked-up-chain, as has since been added to the unreleased SVN head of 
> commons-chain?  Or has that just not been noticed yet?

The key here is Ti doesn't have "one chain to rule them all", but periodically 
uses special purposes chains.  This form chain I'm referring to is not directly 
connected to the main processing chain at all, but is initiated by another 
component.  These special purpose chains I think matches the original intent of 
commons-chain better than as a limited workflow language, again, in my humble 
opinion :).

Don

> 
> Joe
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Joe Germuska <Jo...@Germuska.com>.
>Just as we discovered Chain commands were difficult to use for 
>Struts users (all the casting for one), Ti users will generally 
>write interceptors and not chain commands.  Interceptors are more 
>natural, support around operations better due to easier use local 
>variables, and provider easier access to the Action they are 
>intercepting with no casting.

I'm just wondering when this discovery was made.  I don't recall 
seeing a lot of discussion about it.  I don't know enough about 
WebWork interceptors to argue whether they are easier or not, 
although it seems like if you really want to implement "around" style 
programming, they would fit better, since the model with which Struts 
executes per-mapping commands doesn't really give you anything to 
wrap around.  I guess you can always make a chain with filters; I 
can't think of a time I ever wanted to apply a solution like that, so 
it's pretty abstract to me.  I just don't remember there being much 
discussion about whether commands were easy or hard.

>In Ti, while we do use chain for general request processing, where I 
>think it really shines is decision points, something the CoR is 
>built to solve.  A good example is the chain that creates a form 
>bean.  A chain is called, and the first command that sees it can 
>create it, does, then returns "true" as the responsibility has been 
>assumed.  So in summary, Ti developers will work with chains and 
>some interceptors, while the average Ti application will only need 
>to know interceptors.

Ti depends on commons-chain 1.0.  The LookupCommand in that version 
of commons-chain treats a "true" return value from any called chain 
as a signal to abort the entire chain processing.  Did Ti reimplement 
the idea that some commands would ignore the return value from a 
looked-up-chain, as has since been added to the unreleased SVN head 
of commons-chain?  Or has that just not been noticed yet?

Joe

-- 
Joe Germuska            
Joe@Germuska.com  
http://blog.germuska.com    
"Narrow minds are weapons made for mass destruction"  -The Ex

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Don Brown <mr...@twdata.org>.
This is a good question that deserves a wiki writeup as I'm guessing 
I'll get asked it a lot :)

While chain and xwork interceptors do overlap some in theory, they 
overlap very little in practice.  Chain is a general purpose, chain of 
responsibility pattern that is better suited, IMO, for general request 
processing, initialization, decision points, etc.  XWork interceptors 
are more like Servlet Filters, and are specificly designed to intercept 
an action execution.

Just as we discovered Chain commands were difficult to use for Struts 
users (all the casting for one), Ti users will generally write 
interceptors and not chain commands.  Interceptors are more natural, 
support around operations better due to easier use local variables, and 
provider easier access to the Action they are intercepting with no casting.

In Ti, while we do use chain for general request processing, where I 
think it really shines is decision points, something the CoR is built to 
solve.  A good example is the chain that creates a form bean.  A chain 
is called, and the first command that sees it can create it, does, then 
returns "true" as the responsibility has been assumed.  So in summary, 
Ti developers will work with chains and some interceptors, while the 
average Ti application will only need to know interceptors.

Hope that helps,

Don


Ted Husted wrote:
> On 8/31/05, Don Brown <mr...@twdata.org> wrote:
> 
>>I should really list this out on the wiki site.  The short of it is XWork gives us an Action framework, interceptor
>>chains, expression language support, l18n, validation, and the value stack. 
> 
> 
> Do we need both interceptor chains and CoR chains?
> 
> Would it be possible to code a Struts Request Processor using an
> XWorks interceptor chain?
> 
> -Ted.
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> For additional commands, e-mail: dev-help@struts.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Ted Husted <te...@gmail.com>.
On 8/31/05, Don Brown <mr...@twdata.org> wrote:
> I should really list this out on the wiki site.  The short of it is XWork gives us an Action framework, interceptor
> chains, expression language support, l18n, validation, and the value stack. 

Do we need both interceptor chains and CoR chains?

Would it be possible to code a Struts Request Processor using an
XWorks interceptor chain?

-Ted.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Spring and XWork in Ti

Posted by Don Brown <mr...@twdata.org>.
Joe Germuska wrote:
> So, I really do have work I should be doing, but I couldn't help looking 
> around XWork a little bit, and I'm just wondering why Ti needs to use 
> both it and Spring anyway?
> 
> What are the various services offered by each that aren't offered by the 
> other?

I should really list this out on the wiki site.  The short of it is XWork gives us an Action framework, interceptor 
chains, expression language support, l18n, validation, and the value stack.  WebWork gives us all their result types and 
neat tag libraries that can be used with any template technology.

I like working with XWork and WebWork2 because it is similar enough to Struts classic that we can provide near 
backwards-compatibility, yet it is written very well, and brings a bunch of new features we can get for free. 
Furthermore, I think there is a lot of synergy to be had between the two teams for each to explore new features that can 
be easily shared back and forth.

Don

> 
> Joe
> 
> 
> At 2:44 PM -0500 8/31/05, Joe Germuska wrote:
> 
>> I don't know anything about how XWork will handle message resources, 
>> but what I'm talking about is all internal to Struts anyway, so I'm 
>> not sure that the user needs to be concerned; this is more about an 
>> alternative to all the LocalStrings.properties files which Struts 
>> classes currently have to bootstrap themselves.
>>
>> Until I see it, I won't argue very hard for using Spring as the 
>> message resolver, but I am finding it handy inside my own 
>> applications.  Are there any places in Struts Ti where XWork's message 
>> facilities are being used?
> 
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org