Barracuda - Miscellaneous Features
barracuda.gif (11357 bytes)This document describes some of the miscellaneous features within Barracuda, as well as how to access them.
  1. Detecting Client Side Scripting
  2. Disabling the Back Button
  3. URL Rewriting
  4. DOM Pretty Printing

Detecting Client Side Scripting - As you are probably aware, Barracuda can tell you whether or not a client supports scripting by creating a ViewCapabilities object. This information is particularly useful when rendering components into the DOM--if a client is capable of handling scripting we can generate a much more effective user interface by including Javascript in the output. The problem with this approach is that this ViewCapabilities setting only considered whether or not the client supported scripting; it didn't tell you whether they actually had it enabled. This was really less than optimal.

As of Barracuda 1.0.2, we can now tell whether or not scripting is actually enabled in the client browser! We accomplish this without storing any information in cookies or user session. We can even determine when the client setting changes. Here's how it works.

First of all, whenever an HTTP request comes in to the Barracuda system (either through the ApplicationGateway or the ComponentGateway), we inspect the request to see if there is a special marker parameter ($csjs) which indicates definitively whether or not the client supports scripting. If this value (either true or false) is present, we assume we know for sure, and we process accordingly. If this value is not present, we still determine the result as we used to (by looking at browser type). You can look at ViewUtil.getScriptingType() for details...

Now, the question arises: How does this marker flag get set? Well, when ever we render a page back to the client, any classes that use the component framework (either ComponentGateway or DefaultViewHandler) will allow user code to modify the DOM as needed. Then, right before the page is written out to the client, we add a simple piece of logic which looks at all the forms and links in the page. For each form, we add a hidden field called $csjs whose value is set to false; for links, we append on a ?$csjs=false. These markers basically say "Hey, the client doesn't support scripting!". For more details, look at ScriptDetector.prepareClientResp()... 

In addition to setting these hidden values to false, we also embed a client script (ScriptingCheck.js) in the page. When the client page is loaded, this script will run through all the links and forms on the client, setting $csjs values to true. This effectively modifies the objects capable of generating HTTP requests so that when they are invoked they will tell the server "Hey, the client supports scripting!". Of course, if the client doesn't support scripting, the script won't get run and the values will never change.

With us so far? Ok, great! Now for the last key piece: What about a user manually types in a URL, like GetLogin.event? This link will not have the $csjs marker field, so how can the server tell whether scripting is enabled? Well, in this case (a GET request), the server sees that there is not $csjs marker field, and so it immediately sends back a response that looks something like this:

<html>
  <head>
    <script>
      location.replace('someurl?$csjs=true'); 
    </script>
    <noscript>
      <meta HTTP-EQUIV="REFRESH" CONTENT="0; URL=someurl?$csjs=false">
    </noscript>
  </head>
  <body>
  </body>
</html>

What happens in this case as that the client will immediately send back the exact same request, but this time it will include the $csjs marker value which will again tell us whether or not the client supports scripting. It should be noted that we only do this in the case of GET requests; if we are dealing with a POST, we assume that the page probably came from the server and thus it should really have the marker values already. You can look at ScriptDetector.checkClientReq() for more details. 

As a final point, we should talk about what happen when a client actually changes his scripting settings mid stream. Basically, when this occurs, the client must refresh the page. From that point on, all submits and posts will have the new scripting settings. While it would be nice if a refresh wasn't necessary, there  doesn't seem to be anyway to be notified when the client scripting settings change (and at the same time, its probably not that big of a deal since this particular use case--user swapping scripting settings midstream--is a relatively rare occurence).

The net effect of all this is that the ScriptingType setting in ViewCapabilities will now be much more accurate than it used to be, accurately notifying server side code whether or not the client actually has scripting enabled. And if for some reason you'd really rather just stick with the old behavior, you can always turn off the new approach simply by setting ScriptDetector.DETECT_CLIENT_SCRIPTING_ENABLED = false;  

Cool. 


Disabling the Back Button - Barracuda also makes it easy to disable the back button within client pages. What we mean by this is not that the button itself is physically disabled within the client browser, but rather that a URL gesture (ie. clicking a link, submitting a form, etc) causes the resulting page that is returned from the server to replace the current page in the browser history. This means the user can still go backwards in the browser history, its just that the page which generated the URL gesture is not there to go back to--its been replaced!

To get an idea of what we mean by this, you might want to look at the URL Rewriting / Back Button Example.

Now that you understand what we mean by 'Disabling the Back Button', here's how you would utilize this as a developer. Barracuda's BAction components provide a simple setDisableBackButton() method...if this value is set to true, the component will be rendered so as to prevent the user from going back. What this means is that any markup element which can be controlled using BAction components -- buttons, links, forms, select, and input elements -- can be modified so that when the user invokes them, the resulting page is loaded into the current page of the browser's history, thereby preventing the user from resubmitting, etc.

At this point you may be wondering how it all works. Well, let's just say its magic. Ok, so maybe its not THAT amazing, but the underlying logic is pretty complex. Basically, when we wish to reload a link or submit a page and have the results loaded into the current history location within the browser, we have to invoke some Javascript to do this. In the case of a link (<a> element), it's pretty straightforward: we can just do a location.replace(). In the case of a form, however, it's much more complicated since we need to submit the form (which effectively causes a new page to be loaded). The solution we came up with is pretty nifty.

First, we use dynamic HTML in conjunction with Javascript to create an iframe (IE, Mozilla) or layer (NN). From there, we use Javascript to dynamically create/submit a form to a special Barracuda ParamGateway servlet, which unloads all the form values and caches then in the client's session. Then the ParamGateway redirects the browser to the proper URL (which can be loaded using the location.replace approach described earlier). When the client issues the GET request, the param values are restored from the session cache and processing completes with no one--neither client or server--the wiser.

The bottom line is that this approach solves the back button issues in a manner which is easy to use and will work for a majority of developer needs.

The inspiration for all this came from Brent Ashley [brent@ashleyit.com], who has created the JavaScript Remote Scripting (JSRS) Library. We had to modify Brent's code quite a bit, but are nonetheless deeply indebted to him for this piece of functionality. If you think it's cool (like we do), you might want to drop him a line and say thanks.

Obviously, a Javascript solution will have certain limitations. First and foremost, its only going to work in browsers that support Javascript. We've tested and verified it in IE 5, NN 4, and MZ (NN 6). If you need to use it other places you may have to come up with your own solution. It should also be noted that within NN 4, forms are actually submitted using GET (regardless of whether the form is actually specified to use GET or POST). This is because NN uses layers and they don't support a target of POST. This means if you have really big forms you may run into some size problems. If you do, well, don't use the Back Button Features.

That's about it. While its not a perfect solution, its still pretty dang useful. Enjoy!


URL Rewriting - Barracuda supports the notion of URL Rewriting through a helper class called org.enhydra.barracuda.core.util.http.URLRewriter. This class provides methods used by the rest of Barracuda whenever it needs to generate a URL. URL Rewriting ensures that the servlet can access Http Session information for individual clients, even if the client has cookies turned off.

By default, URL Rewriting is turned off, due to a bug in Enhydra 3.x which we're running against on the main Enhydra site. To turn on URL Rewriting, simply set URLRewriter.REWRITE_URLS = true. You can do this programatically by modifying the actual code, or (the better way) you can set this value dynamically when your system starts up using the Barracuda assembler file (ie. ex4.xml). To use this latter approach, simply add a line like this to the assembler file:

<constant class="org.enhydra.barracuda.core.util.http.URLRewriter"
                name="REWRITE_URLS">true</constant>

It's also important to spell out what this approach doesn't handle. Right now, we are only doing URL rewriting on links manipulated by Barracuda. This means that if you have a link embedded in a template that is NOT processed by Barracuda, that link will not get modified. I believe the XMLC DOM renderer provides some default processing to support URL Rewriting, but we haven't researched that fully (so that may be an option for further exploration).


DOM Pretty Printing - Barracuda's DefaultDOMWriter supports the notion of pretty printing. To turn it on, all you have to do is instantiate your DefaultDOMWriter with a boolean value. Alternatively, you can set the DefaultDOMWriter.defaultPrintPretty = true to make all DOMs use pretty printing by default.

The way we handle pretty printing is by using the Tidy formatter (the version that ships with XMLC) to reformat the resulting markup that comes back after the DOM has been initially rendered. This means that pretty printing is not particularly efficient, and as such should probably NOT be used except for debugging purposes.

Also note that there currently seems to be several bugs in Tidy, whereby it incorrectly inserts spaces into <td> cells that contain only images and no text. In addition, it seems to split <textarea> cells incorrectly (thereby inserting spaces in the control when rendered in the browser). Both of these may have adverse affects on your display, so you probably don't want to use pretty printing for anything other than debugging at this point. If anyone knows how to fix these issues, please let us know.


For all the latest information on Barracuda, please refer to http://barracudamvc.org
Questions, comments, feedback? Let us know...