struts-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Gabriel Belingueres <belingue...@gmail.com>
Subject Re: Can we use the decorator pattern in Actions?
Date Thu, 04 Oct 2012 00:34:08 GMT
If this is a recurring functionality (that is, you use it on several
actions), then implementing it as an interceptor makes perfect sense.

http://struts.apache.org/2.3.4.1/docs/writing-interceptors.html

Gabriel

2012/10/3 Miguel Almeida <miguel@almeida.at>:
> I was speaking with Lukasz today about this, so I'm resurrecting this
> old thread.
>
> The underlying question in my (rather extensive) post is:
>
> How can you perform the following decorator pattern:
>
> public OriginalAction implements Preparable,
> SessionAware,OriginalActionInterface{
>
>   public String someFunctionality(){
>     ....
>   }
> }
>
> Decorate like:
>
> public DecoratedAction implements Preparable, SessionAware,etc{
>   private OriginalActionInterface originalAction; //inject
> OriginalAction here
>   @Secured
>   public String someFunctionality(){
>     // do new stuff
>     orignalAction.someFunctionality();
>   }
> }
>
> Issues:
> 1) Your OriginalAction will probably rely on some objects injected by
> struts (eg: session will probably be used). However, because
> OriginalAction is now only decorating DecoratedAction...those objects
> won't be automatically populated by Struts.
>
>
> The only way I see it is to use Spring IoC to define these needed
> objects in OriginalAction. But it would be neat if that was performed by
> Struts.
>
> What are your thoughts on this?
>
>
> Miguel Almeida
>
>
>  On Wed, 2012-05-16 at 11:22 +0100, Miguel Almeida wrote:
>
>> Imagine the scenario where you have security implemented at the action
>> method level with an annotation:
>>
>> @Secured("someRole") restricts that action to that role (and it is
>> checked with an interceptor).
>>
>> Discussing this on the TDD mailing list a while back, a decorator
>> approach was suggested
>>
>> To separate concerns and ease up testing, authorization is implemented
>> as a decorator (a-la GoF decorator pattern) adding authorization to the
>> underlying (decorated) MVC app.
>>
>> The technique to getting there (see pseudo code in [1])
>> 1. Extract an interface from your main class with all the public methods
>> 2. Implement a decorator which adds authorization rules to a decorated
>> underlying object. The decorator implements the authorization rules
>> using annotations
>> 3. in your tests, test the decorator providing a mock underlying
>> decorated object, asserting in each test that given a request with a
>> user that has certain roles the underlying method should or should not
>> be called.
>>
>>
>> As you see, tests would have a simple setup as you wouldn't be calling
>> "the real, possible complicated action code", but the fake decorated
>> one.
>> The problem arises when you have superclasses (and maybe also when you
>> implement interfaces). I exemplify with both.
>>
>> Imagine this:
>> RealAction extends CommonAction implements IAction(){
>> ...}
>>
>> CommonAction implements ServletRequestAware(){
>> ...
>> }
>>
>> AuthorizingDecorator implements IAction(){
>> //injected decorated IAction, see [1]
>> ...
>> }
>>
>> Now, on a regular RealAction implementation, the request object exists:
>> RealAction extends CommonAction, so the request is injected through its
>> ServletRequestAware.
>> If you're using the AuthorizingDecorator, however, the request will be
>> null: RealAction will be injected, so Struts won't kick in to populate
>> RealAction's request object.
>>
>>
>> My question is: how would you go on and solve this? Or is the decorator
>> approach impractical in Struts? I haven't even consider the necessity to
>> implement every getter/setter on the IAction, which would also make this
>> approach a bit cumbersome. The simplicity for testing, however, is
>> great!
>>
>> Cheers,
>>
>> Miguel Almeida
>>
>>
>> [1] The code might end up like this (semi-pseudo code)
>>
>> 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 IAction
>> {
>>
>>         String MethodA()
>>         String MethodB()
>>         ...
>>
>> }
>>
>> // this is the real action implementing methodA, methodB etc
>> class RealAction: IAction
>> {
>>
>>         String MethodA()
>>         String MethodB()
>>         ...
>>
>> }
>>
>> // this is responsible for authorization
>> class AuthorizingDecoratorAction : IAction
>> {
>>
>>         private IAction _decorated;
>>         public AuthorizationDecorator(IAction decorated)
>>         {
>>         _decorated = decorated;
>>         }
>>
>>         // each method is implemented using annotations and calling the
>>         underlying decorated object
>>         @SecuredRoles("admin, manager")
>>         public void MethodA()
>>         {
>>         _decorated.MethodA();
>>         }
>>
>>         @SecuredRoles("regular user")
>>         public void MethodB()
>>         {
>>         _decorated.MethodB();
>>         }
>>
>> }
>
>

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


Mime
View raw message