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 <mig...@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-unsubscr...@struts.apache.org For additional commands, e-mail: user-h...@struts.apache.org