You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Ben Eng <be...@jetpen.com> on 2005/02/16 19:26:25 UTC

Proposal: EventListener to wrap around listener invocation

I would like to propose a new feature: a new type of EventListener
that a component can implement so that code can be invoked before and
after all listener methods for that component. Maybe something like
this:

public interface ActionInvocationListener extends EventListener
{
    void listenerPreInvoke(ListenerEvent event);

    void listenerPostInvoke(ListenerEvent event);
}

public class ListenerEvent extends EventObject
{
    IRequestCycle getRequestCycle();

    Object getTarget(); // the target object (not necessary)

    Method getMethod(); // the listener method
}


When ListenerMap creates an implementation of IActionListener, if it
detects that the target object implements ActionInvocationListener, it
instantiates an EventfulSyntheticListener instead of an ordinary
SyntheticListener. EventfulSyntheticListener adds a try/finally block
around the listener method invocation to call both the
listenerPreInvoke and listenerPostInvoke methods.

This would be used for implementing security and transaction related
processing. For example, to check whether the user has permission to
perform that action on the objects selected (checkmarked) in the
Form.

I'm also mulling over whether to use this technique to set the current
application context using a ThreadLocal variable, so that the user's
context information is available to all layers of the server
application. e.g., Subject/Principal, permissions, Locale, TimeZone,
and per-request logging (for error reporting or debugging of the
current action).

Comments?

Ben

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


Re: Proposal: EventListener to wrap around listener invocation

Posted by Ben Eng <be...@jetpen.com>.
Erik,

I too considered this problem to be solvable by aspects. However, I
did not want to introduce additional tooling complications into the
build just for this one use.

Until aspects become a core part of J2SE or J2EE, understood by the
javac compiler or by the J2EE enhancer (e.g., BEA's appc), I will
continue to resist applying this technology for problems that can be
solved without much pain in standard Java ways. That's why I chose
this approach.

The security stuff I've built is pretty tied to BEA WLS and MVCSoft
JDO at the moment. If it was more portable, I'd probably be pretty
happy to offload that code to open source. But the way security
providers integrate into an application server and the way this
impacts the JDO PersistenceManagerFactory initialization to deal with
the classloader issues between JMX MBeans and the EAR are not pretty
across appserver implementations.

Maybe if I think about this problem more over time, I might refactor
things so that implementations are pluggable, and I'll release it as a
generalized way to enforce security policies for Tapestry based
apps. I'd be happy to share the code with you privately though, just
not for public consumption.

Ben

On Tue, Mar 22, 2005 at 01:08:14PM -0500, Erik Hatcher wrote:
> Ben,
> 
> This is clever.  Ultimately it's up to Howard & Co. whether this will  
> make it into Tapestry - perhaps this type of hook is already available  
> with HiveMind and 3.1?  Howard?
> 
> This could also have been done using AspectJ.  I struggle with these  
> types of things (this very thing at this very moment actually!) and  
> whether this should be part of the framework or made into aspects.
> 
> I was just looking to make my DirectLink's redirect after they are  
> performed, allowing the page to be refreshed in the browser without  
> duplicating the action - your patch looks like it'd do the trick with a  
> post event hook (though I'm using 3.1).
> 
> 	Erik
> 
> On Mar 21, 2005, at 5:25 PM, Ben Eng wrote:
> 
> >OK, here is the implementation of this proposal. It seems to work
> >pretty well for enforcing role based access control on a method (page
> >listener) level, without having to code the programmatic enforcement
> >on a per-listener method basis.
> >
> >A slightly more sophisticated AbstractPage implementation can also
> >accommodate pages that show or edit access controlled instances (e.g.,
> >ShowUser.page or EditService.page, where the User and Service objects
> >implement an AccessControlled interface to enable instance-based
> >access control).
> >
> >Security policies can be declared and enforced using a scheme similar
> >to the following (depicted in property file format).
> >
> ># everyone is allowed to ShowUser, and also check for read permission
> ># on the User instance
> >example.web.pages.ShowUser=read:*
> >
> ># only users with a user_admin role are allowed to save, and also
> ># check for write permission on the User instance
> >example.web.pages.ShowUser.save=write:user_admin
> >
> >Enjoy!
> >
> >Ben
> >
> >On Wed, Feb 16, 2005 at 01:26:25PM -0500, Ben Eng wrote:
> >>I would like to propose a new feature: a new type of EventListener
> >>that a component can implement so that code can be invoked before and
> >>after all listener methods for that component. Maybe something like
> >>this:
> >>
> >>public interface ActionInvocationListener extends EventListener
> >>{
> >>    void listenerPreInvoke(ListenerEvent event);
> >>
> >>    void listenerPostInvoke(ListenerEvent event);
> >>}
> >>
> >>public class ListenerEvent extends EventObject
> >>{
> >>    IRequestCycle getRequestCycle();
> >>
> >>    Object getTarget(); // the target object (not necessary)
> >>
> >>    Method getMethod(); // the listener method
> >>}
> >>
> >>
> >>When ListenerMap creates an implementation of IActionListener, if it
> >>detects that the target object implements ActionInvocationListener, it
> >>instantiates an EventfulSyntheticListener instead of an ordinary
> >>SyntheticListener. EventfulSyntheticListener adds a try/finally block
> >>around the listener method invocation to call both the
> >>listenerPreInvoke and listenerPostInvoke methods.
> >>
> >>This would be used for implementing security and transaction related
> >>processing. For example, to check whether the user has permission to
> >>perform that action on the objects selected (checkmarked) in the
> >>Form.
> >>
> >>I'm also mulling over whether to use this technique to set the current
> >>application context using a ThreadLocal variable, so that the user's
> >>context information is available to all layers of the server
> >>application. e.g., Subject/Principal, permissions, Locale, TimeZone,
> >>and per-request logging (for error reporting or debugging of the
> >>current action).
> >>
> >>Comments?
> >>
> >>Ben

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


Re: Proposal: EventListener to wrap around listener invocation

Posted by Erik Hatcher <er...@ehatchersolutions.com>.
Ben,

This is clever.  Ultimately it's up to Howard & Co. whether this will  
make it into Tapestry - perhaps this type of hook is already available  
with HiveMind and 3.1?  Howard?

This could also have been done using AspectJ.  I struggle with these  
types of things (this very thing at this very moment actually!) and  
whether this should be part of the framework or made into aspects.

I was just looking to make my DirectLink's redirect after they are  
performed, allowing the page to be refreshed in the browser without  
duplicating the action - your patch looks like it'd do the trick with a  
post event hook (though I'm using 3.1).

	Erik

On Mar 21, 2005, at 5:25 PM, Ben Eng wrote:

> OK, here is the implementation of this proposal. It seems to work
> pretty well for enforcing role based access control on a method (page
> listener) level, without having to code the programmatic enforcement
> on a per-listener method basis.
>
> A slightly more sophisticated AbstractPage implementation can also
> accommodate pages that show or edit access controlled instances (e.g.,
> ShowUser.page or EditService.page, where the User and Service objects
> implement an AccessControlled interface to enable instance-based
> access control).
>
> Security policies can be declared and enforced using a scheme similar
> to the following (depicted in property file format).
>
> # everyone is allowed to ShowUser, and also check for read permission
> # on the User instance
> example.web.pages.ShowUser=read:*
>
> # only users with a user_admin role are allowed to save, and also
> # check for write permission on the User instance
> example.web.pages.ShowUser.save=write:user_admin
>
> Enjoy!
>
> Ben
>
> On Wed, Feb 16, 2005 at 01:26:25PM -0500, Ben Eng wrote:
>> I would like to propose a new feature: a new type of EventListener
>> that a component can implement so that code can be invoked before and
>> after all listener methods for that component. Maybe something like
>> this:
>>
>> public interface ActionInvocationListener extends EventListener
>> {
>>     void listenerPreInvoke(ListenerEvent event);
>>
>>     void listenerPostInvoke(ListenerEvent event);
>> }
>>
>> public class ListenerEvent extends EventObject
>> {
>>     IRequestCycle getRequestCycle();
>>
>>     Object getTarget(); // the target object (not necessary)
>>
>>     Method getMethod(); // the listener method
>> }
>>
>>
>> When ListenerMap creates an implementation of IActionListener, if it
>> detects that the target object implements ActionInvocationListener, it
>> instantiates an EventfulSyntheticListener instead of an ordinary
>> SyntheticListener. EventfulSyntheticListener adds a try/finally block
>> around the listener method invocation to call both the
>> listenerPreInvoke and listenerPostInvoke methods.
>>
>> This would be used for implementing security and transaction related
>> processing. For example, to check whether the user has permission to
>> perform that action on the objects selected (checkmarked) in the
>> Form.
>>
>> I'm also mulling over whether to use this technique to set the current
>> application context using a ThreadLocal variable, so that the user's
>> context information is available to all layers of the server
>> application. e.g., Subject/Principal, permissions, Locale, TimeZone,
>> and per-request logging (for error reporting or debugging of the
>> current action).
>>
>> Comments?
>>
>> Ben
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
>> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> <ActionInvocationListener- 
> patch.tar.gz>---------------------------------------------------------- 
> -----------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


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


Re: Proposal: EventListener to wrap around listener invocation

Posted by Ben Eng <be...@jetpen.com>.
OK, here is the implementation of this proposal. It seems to work
pretty well for enforcing role based access control on a method (page
listener) level, without having to code the programmatic enforcement
on a per-listener method basis.

A slightly more sophisticated AbstractPage implementation can also
accommodate pages that show or edit access controlled instances (e.g.,
ShowUser.page or EditService.page, where the User and Service objects
implement an AccessControlled interface to enable instance-based
access control).

Security policies can be declared and enforced using a scheme similar
to the following (depicted in property file format).

# everyone is allowed to ShowUser, and also check for read permission
# on the User instance 
example.web.pages.ShowUser=read:*

# only users with a user_admin role are allowed to save, and also
# check for write permission on the User instance
example.web.pages.ShowUser.save=write:user_admin

Enjoy!

Ben

On Wed, Feb 16, 2005 at 01:26:25PM -0500, Ben Eng wrote:
> I would like to propose a new feature: a new type of EventListener
> that a component can implement so that code can be invoked before and
> after all listener methods for that component. Maybe something like
> this:
> 
> public interface ActionInvocationListener extends EventListener
> {
>     void listenerPreInvoke(ListenerEvent event);
> 
>     void listenerPostInvoke(ListenerEvent event);
> }
> 
> public class ListenerEvent extends EventObject
> {
>     IRequestCycle getRequestCycle();
> 
>     Object getTarget(); // the target object (not necessary)
> 
>     Method getMethod(); // the listener method
> }
> 
> 
> When ListenerMap creates an implementation of IActionListener, if it
> detects that the target object implements ActionInvocationListener, it
> instantiates an EventfulSyntheticListener instead of an ordinary
> SyntheticListener. EventfulSyntheticListener adds a try/finally block
> around the listener method invocation to call both the
> listenerPreInvoke and listenerPostInvoke methods.
> 
> This would be used for implementing security and transaction related
> processing. For example, to check whether the user has permission to
> perform that action on the objects selected (checkmarked) in the
> Form.
> 
> I'm also mulling over whether to use this technique to set the current
> application context using a ThreadLocal variable, so that the user's
> context information is available to all layers of the server
> application. e.g., Subject/Principal, permissions, Locale, TimeZone,
> and per-request logging (for error reporting or debugging of the
> current action).
> 
> Comments?
> 
> Ben
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org