struts-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Miguel Almeida <mig...@almeida.at>
Subject Re: Can we use the decorator pattern in Actions?
Date Fri, 31 Mar 2017 16:29:04 GMT
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

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