struts-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Lukasz Lenart <lukaszlen...@apache.org>
Subject Re: Can we use the decorator pattern in Actions?
Date Sat, 01 Apr 2017 07:22:03 GMT
Hi Miguel,

I still have this on my TODO list ;-) But to be honest, I have no idea
(or rather forgot) how it should be implemented and I still don't get
it, what's the main reason/functionality?

It looks like a proxy but from user/developer perspective (just for
records, Struts is using ActionProxy internally), but as far I
understand you will code the original action and the decorated one by
hand? there be no proxy magic involved? So all you need is a way to
inject the original action into the decorated action ... which seems
doable ;-)

To start over:

@OriginalAction
public OriginalAction implements Preparable, SessionAware,
OriginalActionInterface {

  public String someFunctionality(){
    ....
  }
}

@DecoratedAction
public DecoratedAction {

 @InjectAction
 private OriginalActionInterface originalAction; //inject OriginalAction here

  @Secured
  public String someFunctionality(){
    // do new stuff
    orignalAction.someFunctionality();
  }
}

<struts>
  <action name="decorated" class="...DecoratedAction">
     ...
  </action
</struts>

having actions as such and the configuration, the flow will be as follow:

http request -> map to the "decorated" entry in struts.xml -> create
instance of the DecoratedAction -> discover @DecoratedAction and/or
@InjectAction (possibility to inject multiple decorated actions???) ->
create instance of the OriginalAction and apply request on it (this
action will be threaten as it will the original mapped to action, in a
classic way) -> inject the original action into the decorated -> call
execute -> continue to result -> response

is the above align to your idea?


Regards
-- 
Ɓukasz
+ 48 606 323 122 http://www.lenart.org.pl/

2017-03-31 18:29 GMT+02:00 Miguel Almeida <miguel@almeida.at>:
> I am resurrecting this very old thread to ask if there have been any updates
> to struts itself to solve this.
> I was reading some comments on this subject on stackoverflow and recalled
> our discussion.
>
> Lukasz - do you know of any developments within Struts in this area?
>
> With regards to your original suggestion, I'm not sure I followed, since
> "Thus must be implemented in each interceptor which interacts with action
> base on interface (Preparable, ValidationAware, SessionAware, etc)." sounded
> like all (or most) Struts  interceptors would need to be re-written.
>
> Miguel
>
>
> On Qui, 2012-10-04 at 08:05 +0200, Lukasz Lenart wrote:
>
> 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();
>>>         }
>>>
>>> }
>>
>>
>
> I thought about that a bit, but as I'm not sure what's the real use
> case is so my proposal can be wrong ;-)
> There are two option (both to extend struts2 itself), beside that you
> can always write your own interceptor.
>
> First is to add additional interface (ActionDecortator) that will mark
> an action as a decorating action the original one and all the
> injections / method calls will be performed onto
> ActionDecorator#getDelegate(). Thus must be implemented in each
> interceptor which interacts with action base on interface (Preparable,
> ValidationAware, SessionAware, etc).
>
> The second option is to add additional interface / annotation just for
> selected existing interceptors, eg. ServletConfigInterceptor and new
> ServletConfigDecorator#getDelegate(). Thus must be only implemented
> with given interceptor.
>
> We can always mix the both ways and start with one interface
> (ActionDecorator) and add the functionality to all the interceptors
> step by step.
>
>
> Regards

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


Mime
View raw message