We're using WebWork 2.2 heavily on a handful of projects (OK, a big handful of big projects), so I definitely understand the concerns.
I didn't mean to shock anyone. I thought my point of view was clear based on the introduction to the "Rough Spots" page (http://wiki.apache.org/struts/RoughSpots) and the "Action Next++" thread (http://forums.opensymphony.com/thread.jspa?threadID=27183). I'm worried about migrating our WebWork projects, too, but I'm willing to stick with WebWork 2.2 for a little longer and endure a less convenient migration in order to support what's best in the long run. (I also don't think a migration will be as painful as some think.) In the long run, do we want Struts Action 2.0 to be a standard on the same footing as JSF or just another non-JSF framework? I want the former. I want Struts Action 2.0 to be the default choice of major corporations so I can continue to use it for years to come. If you agree, the most important thing is that we get the published API right in the 2.0 release. The published API includes a Java API like we have here, the configuration (along with the implicit interceptor and result names), the tag libraries, etc. Breaking the API in a 2.0.x release is not an option; we'll be stuck with whatever we put out in 2.0. As I said in the "Action Next++" thread, I'd rather not start planning on a 3.0 release. Let's get it right the first time. On 5/4/06, Don Brown <[EMAIL PROTECTED]> wrote:
I see this new API as a proposal, meant to feed discussion and not to be voted on as a whole today. Therefore, let us have a solid discussion on the particulars of the API, and avoid throwing out the abused '-1' votes, as those are meant for official votes and carry an obstructive, negative connotation.
Exactly. Thanks, Don.
o.a.s.action2 - I'd like to hear the design reasoning behind the Messages changes. I liked the use of Maps in the XWork design as it made it easier to work with. On the other hand, encapsulating message operations in the Messages object does reduce the number of message-handling methods required. Perhaps Messages could extend Map? Also, I agree we should continue to support plain Messages, as not all apps need to be localized.
- Passing in keys vs. actual messages - I think always passing in keys is one thing Struts got right. Even if you only support one language, abstracting messages out of your code is still a good practice. - Using keys enabled us to do away with the TextProvider interface entirely. - I didn't like having the same set of methods twice: one for errors and one for regular messages. The new design is more object oriented, has shorter method names, enables better reuse of code between errors and normal messages, and leaves the door open to other levels of messages (such as warning). I'm not saying we want to explicitly support arbitrary levels (like JSF does), but we don't want to close the door to it either. - This design doesn't force inheritance. Notice we don't have ActionSupport anymore? If users still want to have the implicit methods, they can statically import them from a support class. The support class implementation would look up the thread local Request and delegate to it. I didn't add this yet because I'm not sure if we really need it. - In the old design, messages were scoped to an action which doesn't work very well when you're chaining and you want to display all the errors from all the actions. I think we want messages to be scoped to the request (i.e. spanning multiple actions). We actually use our own message handling and ignore WebWork's at the moment. - Regarding your Map comment, we've considered having Messages.forFields() return a Map<String, List<String>>. Would that work? That would be identical to what WebWork supports today.
I'm not sure I understand the separation of Validatable and ErrorAware. In particular, Validatable only has a validate() method that returns void. Is there really a case you want to validate, but not have errors sent anywhere? I think of the use case of plugging in a different validation engine like commons-validator, and this separation makes it harder. Why not return Messages?
I've been thinking Validatable should extend ErrorAware, but I wanted to see what you guys thought first. I don't like the idea of validate() return Messages. I never liked the fact that I had to create an errors object in Struts. I also want to be able to easily add validation messages from setters (I like doing field level validation in the setter and cross field validations in validate()).
o.a.s.action2.attribute - This is again a feature I'd like to hear the design reasonings of. I liked the previous use of Maps as they were easy to test and pass around. Maps can also be extended to provide the automatic synchonrization feature talked about easily.
This is something I've been kicking around since generics came out. Now that we have generics, it seems funny to be passing around a heterogeneously typed map. The new way results in better type safety and less code. Here are some examples for comparison: Old way: public class OldWay implements SessionAware { static final String FOO_KEY = Foo.class.getName(); Map<String, Object> session; public void setSession(Map<String, Object> session) { this.session = session; } public String execute() { Foo foo = (Foo) session.get(FOO_KEY); if (foo == null) { foo = new Foo(); session.put(FOO_KEY, foo); } foo.doSomething(); return SUCCESS; } } New way: public class NewWay { Attribute<Foo> fooAttribute = new SessionAttribute<Foo>(Foo.class.getName()) { protected Foo initialValue() { return new Foo(); } }; public String execute() { Foo foo = fooAttribute.get(); foo.doSomething(); return SUCCESS; } } Testing is actually easier--it's easier to mock out Attribute than Map. I also proposed an annotation based approach, but Patrick preferred the attribute API. Here's how that could work: public class AnnotationWay { Foo foo; // result is stored on session, called after execute() but before result. @SessionAttribute public Foo getFoo() { if (foo == null) { this.foo = new Foo(); } return foo; } // parameter pulled from session, called before anything else. @SessionAttribute public void setFoo(Foo foo) { this.foo = foo; } public String execute() { getFoo().doSomething(); return SUCCESS; } } I'm inclined to agree with Pat. The annotation approach is clean and simple, but it conflicts with setting parameters (i.e. how do you prevent setting parameters on session objects for security reasons?) and is a little magical.
o.a.s.action2.servlet - I like how the servlet-related classes are contained in their own package. This distinction is very important as I plan to be personally using Action 2 mostly for Portlets.
I talked with Pat about whether we should build an abstraction layer over the servlet/portlet APIs, and we decided against it. The portlet API really should have tried harder to embrace the servlet API. To support the portlet API, we plan to implement a servlet API adapter to it. The deal breaker for me was that users will be able to reuse the same code inside and outside of our framework. They won't have to port their code from the servlet API to our new abstraction API. And it makes less work for us and fewer new things for users to learn. ;)
o.a.s.action2.spi - Again, I love this separation - move all the framework classes the user rarely deals with out into its own package. I like making ValueStack a first class interface, and the Interceptor changes seem reasonable. I am somewhat concerned about the Request interface though. While the goal of putting everything you need for a request in one object, it seems to be combining too many roles. For one, it has servlet object retrieval methods in there that should be separated, and I'm not sure if it should be handing the execution of actions and interceptors as well. If the goal is to turn this into a Tapestry-like Visitor object which holds all the request state, we should separate out the servlet getters into their own interface to be combined by the user.
We've been playing with some ideas here. First off, actions should pretty much never see this Request object. They still get everything they need through the *Aware interfaces, etc. I'm thinking of creating an ActionContext interface and moving all the information about the currently executing action into there. Then we'd have Request.getCurrentActionContext(), and we could even provide access to the contexts of other actions in the chain if we need to. I'm not sure I understand what you mean about moving the servlet methods into a separate interface. Can you provide an example? To be clear, users wouldn't implement the Request interface, but framework implementors would. Thanks, Bob --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]