[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. If you
+ are have an existing web application in Expresso 5.5, youâll add the
+ following to your web.xml: <programlisting> <filter>
+ <filter-name>request-registry</filter-name>
+ <filter-class>com.jcorporate.expresso.core.registry.RequestRegistryFilter</filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>request-registry</filter-name>
+ <servlet-name>action</servlet-name>
+ </filter-mapping>
+ <filter-mapping>
+ <filter-name>request-registry</filter-name>
+ <servlet-name>DBCreate</servlet-name>
+ </filter-mapping>
+ <filter-mapping>
+ <filter-name>request-registry</filter-name>
+ <servlet-name>PathHandler</servlet-name>
+ </filter-mapping></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