Chapter 13. The Request Registry

Table of Contents

Introduction
Initializing the Request Registry
Using the Request Registry
Getting the Settings
Temporarily Increasing Security Permissions
Destroying the RequestRegistry
Multi-Threaded Programming and the Request Registry
Command-Line Programs and the Request Registry

Introduction

The Registry pattern was been discussed in Patterns of Enterprise Application Architectures 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:

DataObject myObject = new RowSecuredDBObject();
myObject.setRequestingUid(myControllerRequest.getDataContext());
myObject.setDataContext(myControllerRequest.getDataContext());

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:

Initializing the Request Registry

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 MutableRequestRegistry . The usage of the class is simple:

new MutableRequestRegistry(“myDataContext”, myUser);

Where myUser is a com.jcorporate.expresso.core.security.User 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().

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:

<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>

If you create your own stand-alone, non-web program using Expresso, you are going to have to call new MutableRequestRegistry(...) 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.

Using the Request Registry

Getting the Settings

Once the RequestRegistry is set, you can retrieve the settings by using its static method directly: Example:

String dataContext = RequestRegistry.getDataContext();
log.info(&ldquo;Current Thread&rsquo;s Data Context is&rdquo; + &ldquo; dataContext);

Another Example:

User u = RequestRegistry.getUser();
log.info(&ldquo;Current User: &ldquo; + u.toString());

Temporarily Increasing Security Permissions

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:

//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(&ldquo;Current user is: &ldquo; + dbobj.getRequestingUid());  

//Sets the thread default user to admin.
RequestRegistry.superUser(User.getAdmin(RequestRegistry.getDataContext()));
MyDBObject dbobj2 = new MyDBObject();

//Will print out Admin&rsquo;s uid [usually 3]
System.out.println(&ldquo;DBObj2 User is: &ldquo; + dbobj2.getRequestingUid());

//Back out:  
RequestRegistry.revertUser();

//Will print out Super User
System.out.println(&ldquo;Current user is: &ldquo; + RequestRegistry.getUser().toString());

//Revert again
RequestRegistry.revertUser();

//Will print whatever we were before calling superUser()
System.out.println(&ldquo;Current user is: &ldquo; + RequestRegistry.getUser().toString());

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.

try {
	RequestRegistry.superUser(SuperUser.SUPER_USER);
	//.... Do Stuff
} finally {
	RequestRegistry.revertUser();
}

Destroying the RequestRegistry

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:

MutableRequestRegistry registry = new MutableRequestRegistry(&ldquo;default&rdquo;,SuperUser.SUPER_USER);
registry.releaseSettings();

Multi-Threaded Programming and the Request Registry

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 com.jcorporate.expresso.core.registry.ExpressoThreadContext . 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.

Example: Thread 1:

ExpressoThreadContext context = new ExpressoThreadContext();
MyThread t = new MyThread();
t.setContext(context);
t.start();
....

Inside MyThread:

public void run() {
 	this.getContext().applyToCurrentThread(). //Creates a new RequestRegistry for us.
	......
}

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 super.run() .

Example:

class MyThread extends ExpressoThread {
	public MyThread() {
		super();
	}
	
	public void run() {
		super.run();
		//Do the rest of your stuff.
	}
}

The client only needs to treat your object normally:

Thread myThread = new MyThread();
myThread.start();

All the manual RequestRegistry transfer is taken care of for us.

Command-Line Programs and the Request Registry

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

new MutableRequestRegistry(&ldquo;default&rdquo;,SuperUser.SUPER_USER);

will suffice.