CAL and the Tapestry 5 Tutorial

The technique described in my previous post can be used to create Tapestry 5 pages which call CAL functions. Tapestry also uses Javassist to enhance pages, so adding CAL integration requires that Tapestry is reconfigured to apply the CAL transformations in addition to its own — I wasn’t able to find a way to transparently modify the classes before Tapestry sees them.

I’ve modified the Hi/Lo Guessing Game from the Tapestry Tutorial to use CAL implementations for some functions:

The Start page:

@Cal(workspace = "myworkspace.cws", module = "TDavies.Start")
public abstract class Start {
    private final Iterator<Integer> _random = randomList();

    @Cal(outputPolicy=ITERATOR)
    protected abstract Iterator<Integer> randomList();

    @InjectPage
    private Guess _guess;

    Object onAction() {
        _guess.setup(_random.next().intValue());

        return _guess;
    }
}

Note that I have specified an output policy of ITERATOR for the randomList function. This alows us to retrieve lazily calculated random numbers as needed. (in fact, given a page’s lifecycle I think this value is just discarded between games)

The inter-page calls cannot easily be implemented in CAL, as far as I can see, so the setting up of the Guess page remains in Java. That’s a reasonable separation between the UI framework and application logic.

The CAL implementation for the above page is:

randomList ::  [Int];
public randomList = map (\n -> n + 1) $ randomBoundedInts initialSeed 10;

The Guess page:

@Cal(workspace = "myworkspace.cws", module = "TDavies.Start")
public abstract class Guess {
    @Persist
    private int _target;

    void setup(int target)
    {
      _target = target;
    }

    ... the getters and setters are unchanged ...

    @Persist
    private String _message;

    @Cal(in="_target", out="_message")
    abstract String onActionFromLink(int guess);
}

with its CAL implementation:

onActionFromLink :: Int -> Int -> (Maybe String, String);
public onActionFromLink guess target =
    let
        message word = (intToString guess) ++ " is too " ++ word ++ " please try again.";
    in
    (if guess == target then Just "GameOver" else Nothing,
     message (if guess < target then "low" else "high"));

With more in and out values it would become hard to keep track of the identity of the parameters and return values, so a CAL Record might be a better fit.

This is a trivial application, but I like the ability to call CAL directly, rather than delegating to a wrapper class and packing/unpacking parameter structures on call and return.

One Trackback

  1. [...] integrated CAL with a variety of Java based frameworks/environments: Tapestry, GWT and Google AppEngine for [...]

Post a Comment

Your email is never shared. Required fields are marked *

*
*