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