struts-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Miguel Almeida <mig...@almeida.at>
Subject Re: [Idea] Add ability for decorator pattern in Actions
Date Mon, 02 Dec 2013 18:00:57 GMT
Picking up on this, which got lost in my inbox...

On Tue, 2013-07-16 at 12:09 +0200, Lukasz Lenart wrote:

> 2013/7/12 Miguel Almeida <miguel@almeida.at>:
> > I'd like to discuss with you an idea that came up a while ago while
> > trying to fulfil this need:
> >
> > As a developer
> > I want to unit test annotations in my actions without having to run the
> > method's body
> > So that I can TDD more effectively and have quicker unit tests.
> >
> > Namely, imagine an action:
> >
> > @SecuredRoles("admin")
> > public String adminStuff(){
> > ...
> > }
> >
> > It would be interesting to have a way to test the @SecuredRoles without
> > having to run the method's body.
> >
> > Upon discussion within the TDD group, a nice solution was suggested (in
> > italic. Skip below for my comments regarding Struts) :
> >
> > So I would test and implement each aspect in isolation of the other -
> > the authorization would be implemented as a decorator (a-la GoF
> > decorator pattern) adding authorization to the underlaying (decorated)
> > MVC app. BTW I got to this technique by TDDing the separate aspects
> > (this is a good example of where the tests drive the design).
> >
> > The technique to getting there is quite simple:
> > 1. Extract an interface from your main class with all the public methods
> >
> > 2. Implement a decorator which adds authorization rules to a decorated
> > underlaying object. The decorator can implement the authorization rules
> > using your annotations (see this is where the academic meets the
> > practical - you'll in fact be reusing the already existing interceptor
> > but adapting it to a test-driven architecture)
> >
> > 3. in your tests, test the decorator providing a mock underlaying
> > decorated object, asserting in each test that given a request with a
> > user that has certain roles the underlaying method should or should not
> > be called.
> >
> > The code might end up like this (semi-pseudo code but you get the idea)
> >
> >
> > Tests:
> >
> > test_admin_can_call_method_a()
> > {
> > // setup a fake request with admin role:
> > httpRequest = buildRequestWithRole("admin");
> >
> > // setup a mock app decorated with an authorzation decorator:
> > MockApp app = new MockApp();
> > AuthorizationDecorator authorizer = new AuthorizationDecorator(app);
> >
> > // act - try calling method A in the decorator:
> > authorizer.MethodA(httpRequest);
> >
> > // assert - underlaying method a should have been called:
> > Assert(app.MethodA.WasCalled==true);
> > }
> >
> > test_regularUser_cannot_call_method_a()
> > {
> > // setup a fake request with regular user role:
> > httpRequest = buildRequestWithRole("regular user");
> >
> > // setup a mock app decorated with an authorzation decorator:
> > MockApp app = new MockApp();
> > AuthorizationDecorator authorizer = new AuthorizationDecorator(app);
> >
> > // act - try calling method A in the decorator:
> > authorizer.MethodA(httpRequest);
> >
> > // assert - underlaying method a should not have been called:
> > Assert(app.MethodA.WasCalled==false);
> > }
> >
> >
> >
> > In the SUT:
> >
> > interface IApp
> > {
> > void MethodA()
> > void MethodB()
> > ...
> > }
> >
> > // this is the real app implementing methodA, methodB etc
> > class RealApp : IApp
> > {
> > void MethodA()
> > void MethodB()
> > ...
> > }
> >
> > // this is responsible for authorization
> > class AuthorizingDecorator : IApp
> > {
> > private IApp _decorated;
> > public AuthorizationDecorator(IApp decorated)
> > {
> > _decorated = decorated;
> > }
> >
> > // each method is implemented using annotations
> > // and calling the underlaying decorated object
> > @SecuredRoles("admin, manager")
> > public void MethodA()
> > {
> > _decorated.MethodA();
> > }
> >
> >
> >
> > @SecuredRoles("regular user")
> > public void MethodB()
> > {
> > _decorated.MethodB();
> > }
> > }
> >
> > Then in your final MVC application you'd wire up the decorator with the
> > RealApp object:
> >
> > IApp app = new AuthorizingDecorator(new RealApp());
> >
> >
> >
> > This design is incompatible with Struts2 - if you decorate
> > DecoratedAction with OriginalAction, all Struts-related things (e.g.
> > ParamsInterceptor populating Action's fields from request, and I assume
> > every other interceptor's behaviour as well) will no work on
> > DecoratedAction, because it doesn't extend OriginalAction but rather
> > delegates to OriginalAction. E.g, a "someRequestParam" would be
> > populated OriginalAction if it was in the request, but it won't populate
> > originalAction.someRequestParam in DecoratedAction.
> >
> > It would be very interesting to support the Decorator Pattern in Struts
> > actions. What are your thoughts on it?
> 
> Is it similar to ModelDriven?
> 
> The problem I see is how to distinguish when to call decorator and
> when decorated object.

Similar to ModelDriven, in the sense that the model object is also
automatically populated in the action when it implements ModelDriven? If
so, then yes, I believe it's the same.

In terms of calls, calls to the decorated object would be made to build
the object, but in terms of actions, only what is made public in the
decorator would be available. I'm not sure I understand where problems
might arise, can you give an example?


Miguel

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message