ERXComponentActionRedirector Class Reference

Collaboration diagram for ERXComponentActionRedirector:

Collaboration graph
[legend]

List of all members.

Classes

class  Observer
interface  Restorable

Public Member Functions

 ERXComponentActionRedirector (Restorable r)
WOResponse originalResponse ()
WOResponse redirectionResponse ()
String sessionID ()
void setOriginalResponse (WOResponse value)
String url ()

Static Public Member Functions

static void createRedirector (WOActionResults results)
static ERXComponentActionRedirector currentRedirector ()
static ERXComponentActionRedirector redirectorForRequest (WORequest request)

Static Protected Member Functions

static void storeRedirector (ERXComponentActionRedirector redirector)

Protected Attributes

WOResponse originalResponse
WOResponse redirectionResponse
String sessionID
String url

Static Protected Attributes

static final Logger log = Logger.getLogger(ERXComponentActionRedirector.class)
static final NSMutableDictionary responses = new NSMutableDictionary()

Static Package Functions

 [static initializer]

Static Private Attributes

static Observer observer


Detailed Description

Allows you to develop your app using component actions while still providing bookmarkable URLs. It should be considered highly experimental and it uses a few very dirty shortcuts, but no private API to work it's magic. The main problems may be garbage collection or space requirements. You might be better off to compress the responses.
The mode of operation is as follows; given a component action in a typical page:
  public WOComponent myAction() {
      WOComponent nextPage = pageWithName("Main");
      nextPage.takeValueForKey(new Integer(100), "someValue");
      return nextPage;
  }

  
then Main could be implemented something like this:
  public class Main extends WOComponent implements ERXComponentActionRedirector.Restorable {
      static Logger log = Logger.getLogger(Main.class);

      public Integer someValue = new Integer(10);

      public Main(WOContext aContext) {
          super(aContext);
      }

      // this page has a "Increment Some Value" link to itself which just doubles the current value
      public WOComponent addAction() {
          someValue = new Integer(someValue.intValue()*2);
          log.info(someValue);
          return this;
      }

      public String urlForCurrentState() {
          return context().directActionURLForActionNamed("Main$Restore", new NSDictionary(someValue, "someValue"));
      }
      public static class Restore extends WODirectAction {
          public Restore(WORequest aRequest) {
              super(aRequest);
          }
          public WOActionResults defaultAction() {
              WOComponent nextPage = pageWithName("Main");
              Number someValue = context().request().numericFormValueForKey("someValue", new NSNumberFormatter("#"));
              if(someValue != null) {
                  nextPage.takeValueForKey(someValue, "someValue");
              }
              return nextPage;
          }
      }
  }
  
But this is just one possibility. It only locates all the code in one place.

The actual workings are:

When you click on a link, the request-response loop gets executed, but instead of returning the response, we save it in a session-based cache and return a redirect instead. The current page is asked for the URL for the redirect when it implements the Restorable interface.
So the users browser receives redirection to a "reasonable" URL like "/article/1234/edit?wosid=..." or "../wa/EditArticle?__key=1234&wosid=...". This URL is intercepted and looked up in the cache. If found, the stored response is returned, else the request is handled normally.
The major thing about this class is that you can detach URLs from actions. For example, it is very hard to create a direct action that creates a page that uses a Tab panel or a collapsible component because you need to store a tremendous amount of state in the URL. With this class, you say: "OK, I won't be able to totally restore everything, but I'll show the first page with everything collapsed."

For all of this to work, your application should override the request-response loop like:

  public WOActionResults invokeAction(WORequest request, WOContext context) {
      WOActionResults results = super.invokeAction(request, context);
      ERXComponentActionRedirector.createRedirector(results);
      return results;
  }

  public void appendToResponse(WOResponse response, WOContext context) {
      super.appendToResponse(response, context);
      ERXComponentActionRedirector redirector = ERXComponentActionRedirector.currentRedirector();
      if(redirector != null) {
          redirector.setOriginalResponse(response);
      }
  }

  public WOResponse dispatchRequest(WORequest request) {
      ERXComponentActionRedirector redirector = ERXComponentActionRedirector.redirectorForRequest(request);
      WOResponse response = null;
      if(redirector == null) {
          response = super.dispatchRequest(request);
          redirector = ERXComponentActionRedirector.currentRedirector();
          if(redirector != null) {
              response = redirector.redirectionResponse();
          }
      } else {
          response = redirector.originalResponse();
      }
      return response;
  }
 
If you are using ERXApplication, you should set the er.extensions.ERXComponentActionRedirector.enabled=true property instead.

Author:
ak

Constructor & Destructor Documentation

contructs the redirector from the Restorable.

Parameters:
r - Restorable component used to construct a redirector


Member Function Documentation

[static initializer] (  )  [static, package]

static void createRedirector ( WOActionResults  results  )  [static]

Creates and stores a Redirector if the given results implement Restorable.

Parameters:
results 

static ERXComponentActionRedirector currentRedirector (  )  [static]

Uses ERXThreadStorage with the key "redirector".

Returns:
the currently active Redirector in the request-response loop.

WOResponse originalResponse (  ) 

Returns:
the original response.

WOResponse redirectionResponse (  ) 

Returns:
the redirection response.

static ERXComponentActionRedirector redirectorForRequest ( WORequest  request  )  [static]

Parameters:
request The request
Returns:
the previously stored redirector for the given request

String sessionID (  ) 

Returns:
the session ID for the Redirector.

void setOriginalResponse ( WOResponse  value  ) 

Sets the original response.

Parameters:
value the original response.

static void storeRedirector ( ERXComponentActionRedirector  redirector  )  [static, protected]

stores the redirector in the cache.

Parameters:
redirector The redirector to store.

String url (  ) 

Returns:
the URL with which the component can be restored.


Member Data Documentation

final Logger log = Logger.getLogger(ERXComponentActionRedirector.class) [static, protected]

logging support

Observer observer [static, private]

WOResponse originalResponse [protected]

the original response

WOResponse redirectionResponse [protected]

the redirection response

final NSMutableDictionary responses = new NSMutableDictionary() [static, protected]

static cache to hold the responses. They are stored on a by-session basis.

String sessionID [protected]

the session id for the request

String url [protected]

the url for the redirected request


The documentation for this class was generated from the following file:

Generated on Sat May 26 06:43:02 2012 for Project Wonder by  doxygen 1.5.8