Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for 
change notification.

The following page has been changed by ChrisLewis:
http://wiki.apache.org/tapestry/Tapestry5HowToCreateADispatcher2

The comment on the change is:
Accessing request-specific ASOs from a singleton Dispatcher service.

------------------------------------------------------------------------------
- In the article Tapestry5HowToCreateADispatcher we covered the basics of 
creating a Dispatcher and getting it into the pipeline. This quick article is a 
suppliment to that one, continuing the example of implementing an access 
control mechanism. Specifically, we will cover how to access request-specific 
state objects (ASOs) from a singleton service (our access controller).
+ In the article ["Tapestry5HowToCreateADispatcher"] we covered the basics of 
creating a Dispatcher and getting it into the pipeline. This quick article is a 
suppliment to that one, continuing the example of implementing an access 
control mechanism. Specifically, we will cover how to access request-specific 
state objects (ASOs) from a singleton service (our access controller). If you 
haven't already read that article, you should do so before proceeding.
  
  Before reading this be sure to first read about how Tapestry manages 
application state:
  
@@ -11, +11 @@

  
[http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry/annotations/ApplicationState.html
 ApplicationState], 
[http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry/services/ApplicationStateManager.html
 ApplicationStateManager]
  
  == A Glance at the Problem ==
- The access controller we've implemented is a singleton service. It doesn't 
make sense to implement it per-request as the only per-request state it needs 
are the access permissions of the requesting user. However we can't just 
annotate a service field with @!ApplicationState as we normally would in a page 
or component.
+ The access controller we've implemented is a singleton service. It doesn't 
make sense to implement it per-request as the only per-request state it needs 
are the access permissions of the requesting user. However we can't just 
annotate a service field with @!ApplicationState as we normally would in a page 
or component. This annotation ties a field to a request, but singleton services 
have no such association to any request. They are instantiated once and 
accessible by all concurrent requests, at the same time. 
+ 
+ == The Solution in Theory ==
+ If you understand the threadding problem and have read the documentation on 
application state, as well as the javadoc for the !ApplicationStateManager, 
then you know what needs to be done. Our service implementation needs very 
little modification. We simply must obtain a reference to the 
!ApplicationStateManager and explicitly check for the ASO (by class). It has 
the mechanics to check the session of the requesting user, so all we need to is 
ask it for the ASO and it will take care of the dirty work.
+ 
+ Of course this means you must have a class dedicated to the purpose of 
holding access privileges. For our example we'll assume we have such a class 
named !UserPermissions. I can think of 3 ways one might implement the storage 
of this class:
+ 
+  1. Store the !UserPermissions class directly as an ASO. The obvious pro here 
is simplicity: just grab this class and check the contained permission against 
those required.
+  1. Create a higher-level !User class that has a field of type 
!UserPermissions. This makes sense because permissions typically are part of a 
user abstraction.
+  1. Create a general "bucket" class to hold all objects that depend on a 
valid user session, and then store whatever state you need inside it. I see two 
advantages with this method:
+    1. When a user logs out, you can purge all objects by null-ing one state 
object, instead of however many you create.
+    1. I *believe* that T5's ASO implementation only allows you to store one 
object per type. That means that if you wanted to store two different objects 
of the same class, well, you couldn't! By using a general bucket you can store 
what you like.
+ 
+ Whatever strategy you choose, the fundamentals are the same.
+ 
+ == A Solution in Code ==
+ 
+ Here is how we could implement the solution. Assume that we have a class 
named !UserPermissions for storing the permissions, and that it contains a 
method named canAccess. This method returns a boolean showing if the user can 
access the resource (page) represented by the 
[http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry/services/Request.html
 Request] object.
  
  {{{
  import java.io.IOException;
@@ -22, +39 @@

  
  public class AccessController implements Dispatcher {
        
+       /* Our state manager. */
        private ApplicationStateManager asm;
        
+       /**
+        * Receive our state manager as a constructor argument. When we bind 
this
+        * service, T5 IoC will intelligently provide the state manager - 
batteries included! 
+        */
        public SingletonAccessControllerImpl(ApplicationStateManager asm) {
                this.asm = asm;
        }
@@ -31, +53 @@

        public boolean dispatch(Request request, Response response) throws 
IOException {
                boolean canAccess = false;
                
+               /*
+                * Per the application state documentation, we check for the 
existence of an
+                * ASO before attempting access. These prevents any unnecessary 
overhead
+                * (automatic session creation).
+                */
                if(asm.exists(UserPermissions.class)) {
+                       UserPermissions perms = asm.get(UserPermissions.class);
-                       
+                       /*
+                        * The object referenced by 'perms' is an instance 
specific to
+                        * the current request, which is what we need. Now 
check the
+                        * permissions against the resource - how you do this 
of course
+                        * depends on your resource restriction implementation. 
However
+                        * you will most likely base this on the page (page 
name or
+                        * class).
+                        */
+                       canAccess = perms.canAccess(request);
                }
                
                if(!canAccess) {
@@ -50, +86 @@

  }
  }}}
  
+ Some quick notes on the implementation:
+ 
+  1. We get our !ApplicationStateManager once - as a constructor argument. If 
we auto-bind our service, T5 IoC will magically take care of everything. If we 
want to build it ourselves in our app module, we simply need to @Inject the 
!ApplicationStateManager as an argument to our builder method.
+  1. To keep reduce session overhead, we avoid creating it if the ASO we need 
doesn't exist.
+ 
+ == Conclusion ==
+ 
+ It has been noted on the mailing list that access control can be implemented 
using this same technique, but as a 
[http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry/services/RequestFilter.html
 RequestFilter] instead. I haven't tried this but the same concepts regarding 
ASOs apply.
+ 
+ Any suggestions, corrections, or other furtherings on this document are most 
welcome. If you'd like to chat with me about this, you can find me in #tapestry 
on irc.freenode.net (chrislewis).
+ 

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to