Help

Inactive Bloggers
16. Dec 2007, 09:23 CET, by Gavin King

Several times, I've encountered the following view:

Interfaces in Java don't have any semantics attached. Only a concrete class can define the semantics of a method.

I've always thought that this was a very strange thing to believe. The /semantics/ of an object or operation are whatever a human user understands the object or operation to represent. The /implementation/ of an operation is primarily a set of instructions to the machine - and of course the machine has no use for semantics.

So if the semantics of an object or operation do not reside in the implementation of the object or method, exactly where are the semantics defined?

Well, I would argue that the semantics are declared in two places:

  1. The names of things
  2. The JavaDoc

These are the places where we find /English/ words in our code; therefore, they are meant for /human/ consumption, not machine consumption. The machine is every bit as confortable with a method called A$_128__() of a class named a$aaBxw as it is with the submit() method of Order. Only semantics need to be expressed in English.

And when we look at a Java interface, we see that it contains very little extra information beyond a list of names and JavaDoc. So, in fact, an interface is as close to a pure declaration of semantics as you're ever going to find in Java source code! If interfaces don't have semantics:

  1. How would we know what to call them?
  2. What would we write in the JavaDoc?

Of course, an implementation of an interface can add additional semantics - indeed, any subtype of an abstract type /must/, by definition, add additional semantics. But that doesn't mean that the most abstract type in a type heirarchy has /no/ semantics.

Well, except, perhaps, for Object. Does Object have semantics? It's operations certainly do, but what about the class itself? Let's pretend for a second that Java's type system is not completely broken: there are no primitive types, so all types extend Object. Then does it /mean/ anything to know that something is an Object? I'm not sure. Let's leave that as an exercise for the comment thread ;-)

But one thing I /am/ certain about: when we declare that our object implements an interface, we're definitely saying something /meaningful/ about what kind of thing it is.

14. Dec 2007, 22:55 CET, by Pete Muir

One of the features I am most pleased to see in Seam 2.0.1 is Natural Conversations. Why?

Easy redirect to existing conversations

It can be useful to redirect to an existing conversation if the user requests the same operation twice.

Take this example:

You are on ebay, half way through paying for an item you just won as a Christmas present for your parents. Lets say you're sending it straight to them - you enter your payment details but you can't remember their address. You accidentally reuse the same browser window finding out their address. Now you need to return to the payment for the item.

With a natural conversation its really easy to have the user rejoin the existing conversation, and pick up where they left off - just have them to rejoin the payForItem conversation with the itemId as the conversation id.

User friendly URLs

I've always been a strong believer in the use of user friendly, descriptive, URLs. For some applications this is of less import, of course - the largest (pre Seam) application I wrote was really bad at this as it used frames ;-) . For me this consists of:

  • a navigable hierarchy - I can navigate by editing the url
  • a meaningful URL (like this Wiki uses -- so don't identify things by random ids)

The first of these is certainly possible in Seam with the use of URLRewrite (I'm also looking forward to seeing stronger integration between URLRewrite and Seam's pages.xml), but the second was harder until now.

Now, with natural conversations, when you are building your hotel booking system (or, of course, whatever your app is) you can generate a URL like http://seam-hotels/book.seam?hotel=BestWesternAntwerpen (of course, whatever parameter hotel maps to on your domain model must be unique) and with URLRewrite easily transfor this to http://seam-hotels/book/BestWesternAntwerpen.

Much better!

Deprecates explicit synthetic conversation ids

I really didn't like the use of explicit synthetic conversation id - they just feel really ugly to me. You know that gut feeling you get about some things? Explicit synthetic conversaton ids are like that for me.

This is available in the recently released 2.0.1.CR1.

I hope this inspires you to go out and think about how you can incorporate natural conversations into your application.

Well, help is on hand. Jacob Orshalick wrote an excellent article on nested conversations which he seems to be making into bit of series with this latest blog posting on conversation timeouts.

Enjoy!

A robust web application should not crash and die when the session times out. I guess we can all agree on that, but thanks to the stateless nature of HTTP and the usual hacks attaching session state onto that protocol, this is quite difficult to accomplish. Just search for session timeout on Google. So here I am with my JSF/Seam/Ajax4JSF/jQuery application, trying to make it more robust.

Session timeout happens on the server

Well, duh. The HTTP session is stored on the server in some fashion. Of course you could be one of the radicals who think that RIA means that the client keeps all the session state, or that you don't need no stinkin' session because you are all REST. Well, show me your app and we'll talk. You just have whitepapers to show? Too bad.

If you keep session state on the server, and naturally it's cleaned up and timing out on the server-side only, your client doesn't know anything about that. So if you want to do anything on the page your user is looking at when the session times out, you need to poll the server.

In my Seam app I need something to poll so I created the following component that runs on the server:

@Name("httpSessionChecker")
@Scope(ScopeType.APPLICATION)
public class HttpSessionChecker {

    @WebRemote
    public boolean isNewSession() {
        return ServletContexts.instance().getRequest().getSession().isNew();
    }
}

I know that this is extremely sophisticated. Here is the trick: When you ask the server if the session has timed out, you need to ask it if the current session it has is new. You have no other way to find out if the (previous) session timed out. Because your poll request will create a new session if the previous one timed out. So if you happen to check isNewSession() after the previous session timed out, you get a true result. (By the way, who had the braindead idea that Tomcat should re-use session identifiers? How incompetent can you be?)

Polling the server

At that point I still don't know what I want to do on the client when a new session happens to be present on the server. Well, first I need to find out if that is the case by polling the server:

<script type="text/javascript" 
        src="#{wikiPreferences.baseUrl}/seam/resource/remoting/resource/remote.js"></script>
<script type="text/javascript" 
        src="#{wikiPreferences.baseUrl}/seam/resource/remoting/interface.js?httpSessionChecker"></script>

<script type="text/javascript">

    var sessionChecker = Seam.Component.getInstance("httpSessionChecker");
    var timeoutURL = '#{wiki:renderURL(wikiStart)}';
    var timeoutMillis = '#{sessionTimeoutSeconds}'*1000+3000;
    var sessionTimeoutInterval = null;

    function startSessionTimeoutCheck() {
        sessionTimeoutInterval = setInterval('sessionChecker.isNewSession(alertTimeout)', timeoutMillis);
    }

    function stopSessionTimeoutCheck() {
        if (sessionTimeoutInterval) clearInterval(sessionTimeoutInterval);
    }

    function resetSessionTimeoutCheck() {
        stopSessionTimeoutCheck();
        startSessionTimeoutCheck();
    }

    function alertTimeout(newSession) {
        if (newSession) {
            clearInterval(sessionTimeoutInterval);
            jQuery(".ajaxSupport")
                   .removeAttr('onblur')
                   .removeAttr('onchange')
                   .removeAttr('onkeyup')
                   .removeAttr('onclick');
            jQuery(".sessionEventTrigger").hide();
            var answer = confirm("#{messages['lacewiki.msg.SessionTimeout']}");
            if (answer) window.location = timeoutURL;
        }
    }
</script>

First thing, I import the Seam Remoting JavaScript interfaces and the proxy interface of my server-side component, httpSessionChecker. The two main functions I define on the client are startSessionTimeoutCheck() and stopSessionTimeoutCheck(). The start function starts polling the server at an interval. This interval is not just some random millisecond value. I poll the server every sessionTimeoutSeconds plus 3 seconds (3000 milliseconds). So, if the session timeout configured on the server is 30 minutes, I poll it every 30 minutes and 3 seconds, unless somebody resets the interval by calling resetSessionTimeoutCheck(). This basically guarantees that, if no request happened while this browser window is sleeping, the server-side session will be gone when I poll again.

Those three methods (start, stop, reset) will be useful later when I integrate the session timeout checking with the rest of the user interface. Let's look at what I'm doing in the callback of repeated server poll, alertTimeOut(newSession):

  • If the server says that there is no new session, I continue polling it with an unchanged interval.
  • If the server says there is a new session, I stop polling by clearing the interval. Then I react to the new session by modifying the UI on the client side.

So from that point on, I'm handling a client callback and I can do whatever I want to react to the new session.

Adapting the client

My goal is to not just kick the user out when a session timeout occurs. I don't want to just redirect him to some start page, I want to provide a choice. But I also don't want him to do anything dangerous that could throw an exception after his session is gone.

The user can either click OK or Cancel on the confirmation dialog. If OK is clicked, I redirect to the start page, otherwise he can stay on the current page. That is going to be a problem because the current page might have all kinds of widgets on it that really really require a session with some data when you click them.

So first, I disable anything that could be dangerous, using jQuery. The first jQuery statement removes all JavaScript events from any elements on the page that have CSS class of ajaxSupport. The second statement hides any elements on the page that have a CSS class of sessionEventTrigger. Elements that have class ajaxSupport are typically input fields that have onblur event triggers, or onclick links.

The user can continue copying stuff out of these input fields (to preserve data that would otherwise be lost) but he can not trigger an AJAX request anymore. He can also not click on any buttons or see any elements that might require a session.

So all of it comes really down to these two questions:

  • Which pages require a session timeout check? Sometimes I just don't care about the server-side session because all actions on a given page might be safe, no matter if they run in the previous or a new HTTP session.
  • Which elements on a page do I want to hide and what actions do I want to disable if the server-side session times out (if the user doesn't accept the redirect to the start page)?

If a page requires a session timeout check, I add the following code to its body:

<script type="text/javascript">startSessionTimeoutCheck();</script>

When the page is loaded, I start polling the server (with the given interval). If a new session is present on the server, all elements that are marked as styleClass="ajaxSupport" are stripped of their event handlers with jQuery. This would typically be some input field on a form on the page:

<s:decorate id="userNameDecorate" template="formFieldDecorate.xhtml">
    <ui:define name="label">#{messages['lacewiki.label.commentForm.Name']}</ui:define>
    <h:inputText styleClass="ajaxSupport" tabindex="1" size="40" maxlength="100" required="true"
                 id="userName" value="#{commentHome.instance.fromUserName}">
        <a:support status="commentForm:status" event="onblur" 
                   reRender="userNameDecorate" oncomplete="onAjaxRequestComplete()"/>
    </h:inputText>
</s:decorate>

If a new session is present on the server, the confirmation dialog appears. If the user clicks Cancel, the onblur event on that input field will be disabled. The user can still copy and rescue the value he typed in.

All elements of class sessionEventTrigger will be hidden at that point. These are typically buttons such as Save, Update, etc. Here is an example:

<a:commandLink id="post"
                action="#{commentHome.persist}" tabindex="1"
                reRender="commentDisplayForm, messageBoxContainer"
                accesskey="#{messages['lacewiki.button.commentForm.Post.accesskey']}"
                status="commentForm:status"
                eventsQueue="ajaxEventQueue"
                oncomplete="onAjaxRequestComplete()"
                styleClass="button sessionEventTrigger">
    <h:outputText escape="false" styleClass="buttonLabel" 
                  value="#{messages['lacewiki.button.commentForm.Post']}"/>
</a:commandLink>

Just a coincidence, this is a button that doesn't trigger page navigation put a partial page-rendering after completion of the AJAX request. Now, that is an additional complication we need to take into account.

Dealing with AJAX requests

If you request a page and the session poll interval starts running when the page is rendered, everything is fine. The poll interval will be /session timeout/ + 3 seconds (that's just a safety margin). So, while you are focused on that page and working on it, no request is send to the server and both client and server keep counting the seconds. The server times out after /session timeout/ and 3 seconds later the client asks it if there is a new session present. The server should answer /yes/.

AJAX changes that picture completely. A page that contains AJAX actions supports, by definition, partial re-rendering of that page. So while your session poll interval for the page starts running on the client, you make AJAX requests to the server (trigger onblur events, clicking AJAX buttons, etc.). The client poll interval and the server session timeout are now out of sync. So after every AJAX request completes, you have to reset the client poll interval. That is the job of the oncomplete="onAjaxRequestComplete()" callback you have seen on the code snippets above.

Here is what that JavaScript function does:

function onAjaxRequestComplete() {
    resetSessionTimeoutCheck();
}

I guess you could call the reset directly but I like the indirection. Sometimes I need other things to be done after an AJAX request completes (like, apply some CSS styles to the re-rendered parts of the page). I actually would really like to have a default callback for all Ajax4JSF events.

Finally, I can use the start/stop functions of the session check polling conditionally. Let's say I have a page that doesn't require any session checking, all actions and links are perfectly safe to use with an old or new session.

Except that this page might also, conditionally, include a form with plenty of AJAX magic. So I need to enable session state polling when the form is included and shown, and disable it when the form is not shown. Basically, I need to start and stop polling conditionally on the same page. Easy enough:

<s:fragment rendered="#{commentHome.showForm}">
    <script type="text/javascript">startSessionTimeoutCheck();</script>
</s:fragment>

And the opposite, which would (probably) be the default condition when the page is loaded first time:

<s:fragment rendered="#{not commentHome.showForm}">
    <script type="text/javascript">stopSessionTimeoutCheck();</script>
</s:fragment>

It's fine to stop the polling even if it didn't start, the JS function is safe.

Well, that's about it and I hope we can roll some of that back into the Seam and Ajax4JSF codebase to make it easier.

13. Dec 2007, 02:26 CET, by Emmanuel Bernard

There has been a couple of interesting blog entries about Hibernate Shards and data sharding / partitioning in the last few days (here and there). Both give a decent five / ten minutes overview of Hibernate Shards.

We are also planning to do a full talk about the project at JBoss World Orlando in february.

Showing 1026 to 1030 of 1255 blog entries