[cvs] expresso commit by mtraum: new Request Registry chapter

JCorporate Ltd jcorp at jcorp2.servlets.net
Mon Nov 15 20:14:21 PST 2004


Log Message:
-----------
new Request Registry chapter

Modified Files:
--------------
    expresso/expresso-web/expresso/doc/edg:
        edg.xml

Added Files:
-----------
    expresso/expresso-web/expresso/doc/edg:
        request_registry.xml
    expresso/expresso-web/expresso/doc/images/edg:
        request_registry_flow.gif

Revision Data
-------------
Index: edg.xml
===================================================================
RCS file: /home/javacorp/.cvs/expresso/expresso/expresso-web/expresso/doc/edg/edg.xml,v
retrieving revision 1.51
retrieving revision 1.52
diff -Lexpresso-web/expresso/doc/edg/edg.xml -Lexpresso-web/expresso/doc/edg/edg.xml -u -r1.51 -r1.52
--- expresso-web/expresso/doc/edg/edg.xml
+++ expresso-web/expresso/doc/edg/edg.xml
@@ -9,6 +9,7 @@
 	<!ENTITY dbobjtypes SYSTEM "dbobject-types.xml">
 	<!ENTITY controllers SYSTEM "controllers.xml">
 	<!ENTITY validation SYSTEM "validation.xml">
+	<!ENTITY request_registry SYSTEM "request_registry.xml">
 	<!ENTITY dbmaint SYSTEM "dbmaint.xml">
 	<!ENTITY jsp SYSTEM "jsp.xml">
 	<!ENTITY taglib SYSTEM "taglib.xml">
@@ -69,6 +70,7 @@
 	&dbobjtypes;
 	&controllers;
 	&validation;
+	&request_registry;
 	&dbmaint;
 	&connectionpool;
 	&jsp;
--- /dev/null
+++ expresso-web/expresso/doc/edg/request_registry.xml
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter>
+  <title>The Request Registry</title>
+
+  <section>
+    <title>Introduction</title>
+
+    <para>The Registry pattern was been discussed in <citetitle>Patterns of
+    Enterprise Application Architectures</citetitle> by Martin Fowler. It is
+    widely considered that the Registry Pattern should only be applied to
+    specific areas in an application where functions are passing parameters
+    that are never actually used, but only passed down to lower layers in the
+    architecture. Expresso is a classic case of the need for this. The
+    persistence layer requires the data context, and the user security: most
+    of the domain layers could care less. The end result is that you end up
+    with code like:<programlisting>DataObject myObject = new RowSecuredDBObject();
+myObject.setRequestingUid(myControllerRequest.getDataContext());
+myObject.setDataContext(myControllerRequest.getDataContext());</programlisting></para>
+
+    <para>And every domain object will have to pass around String and integer
+    parameters, cluttering up the API, and possibly even more importantly,
+    tying the domain logic explicitly to Expresso, preventing good unit
+    testing. Expresso 5.6, now adds the concept of the “RequestRegistry” that
+    can be found in com.jcorporate.expresso.core.registry. The RequestRegistry
+    implements the Registry pattern by using Thread local variables to store
+    the current thread’s data context and logged in user identity. The General
+    Flow of the Request Registry down through the layers of your program is as
+    follows:<mediaobject>
+        <imageobject>
+          <imagedata fileref="../images/edg/request_registry_flow.gif" />
+        </imageobject>
+      </mediaobject></para>
+  </section>
+
+  <section>
+    <title>Initializing the Request Registry</title>
+
+    <para>The RequestRegistry API consists of static methods which
+    transparently access the ThreadLocal variables on your behalf. So it
+    appears to the client that it is merely calling a static class. But there
+    are no setters. So how does one initialize the RequestRegistry in the
+    first place? The answer lies in the class
+    <classname>MutableRequestRegistry</classname>. The usage of the class is
+    simple:<programlisting>new MutableRequestRegistry(“myDataContext”, myUser);</programlisting></para>
+
+    <para>Where myUser is a
+    <classname>com.jcorporate.expresso.core.security.User</classname> object
+    that you retrieve. Once the RequestRegistry is defined then all dbobjects
+    that are running within that thread will return “myDataContext” when a
+    call to getDataContext().</para>
+
+    <para>So where does this call to create a MutableRequestRegistry begin?
+    For a standard Servlet Environment, RequestRegistry is set in the
+    RequestRegistryFilter: a servlet filter that intercepts all the incoming
+    controller requests and sets security permissions. In other words, for an
+    Expresso web application, make sure your web.xml specifies the filter
+    information just like the the web.xml in the Expresso source.&nbsp; If you
+    are have an existing web application in Expresso 5.5, you’ll add the
+    following to your web.xml: <programlisting>    &lt;filter&gt;
+        &lt;filter-name&gt;request-registry&lt;/filter-name&gt;
+        &lt;filter-class&gt;com.jcorporate.expresso.core.registry.RequestRegistryFilter&lt;/filter-class&gt;
+    &lt;/filter&gt;
+    &lt;filter-mapping&gt;
+        &lt;filter-name&gt;request-registry&lt;/filter-name&gt;
+        &lt;servlet-name&gt;action&lt;/servlet-name&gt;
+    &lt;/filter-mapping&gt;
+    &lt;filter-mapping&gt;
+        &lt;filter-name&gt;request-registry&lt;/filter-name&gt;
+        &lt;servlet-name&gt;DBCreate&lt;/servlet-name&gt;
+    &lt;/filter-mapping&gt;
+    &lt;filter-mapping&gt;
+        &lt;filter-name&gt;request-registry&lt;/filter-name&gt;
+        &lt;servlet-name&gt;PathHandler&lt;/servlet-name&gt;
+    &lt;/filter-mapping&gt;</programlisting></para>
+
+    <para>If you create your own stand-alone, non-web program using Expresso,
+    you are going to have to call <classname>new
+    MutableRequestRegistry(...)</classname> first thing in your program once
+    ConfigManager is initialized to provide standard security mechanisms. If
+    you do not, then ConfigManager sets superUser for the initialization
+    thread and you will have those credentials.</para>
+  </section>
+
+  <section>
+    <title>Using the Request Registry</title>
+
+    <section>
+      <title>Getting the Settings</title>
+
+      <para>Once the RequestRegistry is set, you can retrieve the settings by
+      using its static method directly: Example:<programlisting>String dataContext = RequestRegistry.getDataContext();
+log.info(“Current Thread’s Data Context is” + “ dataContext);</programlisting></para>
+
+      <para>Another Example:<programlisting>User u = RequestRegistry.getUser();
+log.info(“Current User: “ + u.toString());</programlisting></para>
+    </section>
+
+    <section>
+      <title>Temporarily Increasing Security Permissions</title>
+
+      <para>Sometimes you want created objects to have superuser permissions
+      or impersonate another user for security reasons. RequestRegistry has a
+      stack-based method of doing this, much in the way that Unix shells have
+      the su command followed by exit to leave: Example:<programlisting>//Eleveate to Super User Status
+RequestRegistry.superUser(SuperUser.SUPER_USER);
+MyDBObject dbobj = new MyDBObject();  
+
+//Will print out the super user id (-1)
+System.out.println(“Current user is: “ + dbobj.getRequestingUid());  
+
+//Sets the thread default user to admin.
+RequestRegistry.superUser(User.getAdmin(RequestRegistry.getDataContext()));
+MyDBObject dbobj2 = new MyDBObject();
+
+//Will print out Admin’s uid [usually 3]
+System.out.println(“DBObj2 User is: “ + dbobj2.getRequestingUid());
+
+//Back out:  
+RequestRegistry.revertUser();
+
+//Will print out Super User
+System.out.println(“Current user is: “ + RequestRegistry.getUser().toString());
+
+//Revert again
+RequestRegistry.revertUser();
+
+//Will print whatever we were before calling superUser()
+System.out.println(“Current user is: “ + RequestRegistry.getUser().toString());</programlisting></para>
+
+      <para>For security reasons, always surround your superUser with
+      try/finally blocks to ensure proper reverting to previous credentials.
+      Expresso sets new credentials with each request to limit damage if you
+      forget, but it is still a good practice.<programlisting>try {
+	RequestRegistry.superUser(SuperUser.SUPER_USER);
+	//.... Do Stuff
+} finally {
+	RequestRegistry.revertUser();
+}</programlisting></para>
+    </section>
+
+    <section>
+      <title>Destroying the RequestRegistry</title>
+
+      <para>Because of ramifications, we don’t make it easy to destroy the
+      request registry settings. But it is possible. It’s a two step process:
+      Create a new MutableRequestRegistry() and then destroy it. This is how
+      you do it in a nutshell:<programlisting>MutableRequestRegistry registry = new MutableRequestRegistry(“default”,SuperUser.SUPER_USER);
+registry.releaseSettings();</programlisting></para>
+    </section>
+
+    <section>
+      <title>Multi-Threaded Programming and the Request Registry</title>
+
+      <para>You may recall how it was stated that the RequestRegistry uses
+      ThreadLocal variables to set its data. Well, that becomes a problem if
+      you spawn a new thread: All ThreadLocal variables won’t automatically
+      transfer over there. There are two ways of doing this: slightly manual
+      and fully automatic. Both ways center around the class
+      <classname>com.jcorporate.expresso.core.registry.ExpressoThreadContext</classname>.
+      This class copies the RequestRegistry settings when it is created, and
+      applies them to the thread that calls applyToCurrentThread(), thus
+      creating a stable RequestRegistry for the new thread.</para>
+
+      <para>Example: Thread 1:<programlisting>ExpressoThreadContext context = new ExpressoThreadContext();
+MyThread t = new MyThread();
+t.setContext(context);
+t.start();
+....</programlisting></para>
+
+      <para>Inside MyThread:<programlisting>public void run() {
+ 	this.getContext().applyToCurrentThread(). //Creates a new RequestRegistry for us.
+	......
+}</programlisting></para>
+
+      <para>Of course, this is acutlly a bit of a bother, so Expresso provides
+      the com.jcorporate.expresso.core.registry.ExpressoThread class to do
+      this for us. All we have to do is make sure that inside our run()
+      method, we call <methodname>super.run()</methodname>.</para>
+
+      <para>Example:<programlisting>class MyThread extends ExpressoThread {
+	public MyThread() {
+		super();
+	}
+	
+	public void run() {
+		super.run();
+		//Do the rest of your stuff.
+	}
+}</programlisting></para>
+
+      <para>The client only needs to treat your object
+      normally:<programlisting>Thread myThread = new MyThread();
+myThread.start();</programlisting></para>
+
+      <para>All the manual RequestRegistry transfer is taken care of for
+      us.</para>
+    </section>
+
+    <section>
+      <title>Command-Line Programs and the Request Registry</title>
+
+      <para>Whenever you create a new program, make sure you call new
+      MutableRequestRegistry(“default”, ...); to set the default request
+      registry as soon as ConfigManager is done initializing. If your program
+      has no concept of security then <programlisting>new MutableRequestRegistry(“default”,SuperUser.SUPER_USER);</programlisting></para>
+
+      <para>will suffice.</para>
+    </section>
+  </section>
+</chapter>
\ No newline at end of file


More information about the cvs mailing list