Mike Ward pushed a release candidate out for his excellent
Waffle web
framework. Waffle has previously been compared to Ruby of
Rails,
but that's not right really. Waffle has no scaffolding
concept,
no generation of pages/experience, no ActiveRecord for magic CRUD
binding.
Waffle does do a magic binding from forms in web pages to methods in
Java classes. Action methods can be multi parameter methods
that
tightly map to the web form. It also does avoid XML, like it were a
disease. Until someone corrects me, I believe that it gives
you
the lowest lines of code for an action framework.
Waffle leaves you many choices for 'view' technology - JSP, Velocity,
Freemarker, and many choices for persistence - iBatis and Hibernate
(and more).
It also gives you two ways of 'marking up' the linkage from the web
form (or AJAX invocation) to you action class method: Via
pragma
and via
Paranamer. Pragma means the url itself needs to have
some
encoding in it and annotations must be used above the action methods,
Paranamer means that from the fields available in the query string or
POST, the method signature will be constructed before invocation.
My personal favorite sweet spot is Waffle in Paranamer mode, with
Freemarker as view technology, iBatis for DB, with Sitemesh (or course)
decorating all the pages. I do not like the freemarker .ftl
suffix. Not because there is anything wrong with it, but because
DreamWeaver (as it ships by default) has a fixed set of file types that
it can work with. Thus, I have my freemarker templates as
.htm
files so they are dreamweaver ready. This allows for UI
professionals to get involved in the actual commits right?
Well
perhaps if they're trained up in Perforce or Subversion.
When you're working on a Waffle application, you're left with precious
little code to write, and consequentially unit test. Err, I mean
precious little tests to write then implement. It feels like
something is wrong. Dependencies for actions and session /
application level components are chained together with constructors in
a dependency injection style. PicoContainer is (invisibly)
used
to do that, but Google's Guice could be a second implementation quite
easily.
Waffle is not alone in this style to web app. VRaptor is
going
down the same road, and Stripes is similar but has big love for
@nnontaions.
So my contribution is the green man on the waffle front page. Mike
chose the name waffle itself, and after much trawling for images I
could purloin in a "Waffleman style" and a huge period trying to
convince mike to abandon the name Waffle, I just plucked a martian from
iStockPhoto.
Some examples. A calculator action. Note that it is
coincidentally a POJO:
1 package com.thoughtworks.waffle.example.paranamer.action;
2
3 public class CalculatorAction {
4 public Number result;
5
6 public Number getResult() {
7 return result;
8 }
9
10 public void add(int firstNumber, int secondNumber) {
11 result = firstNumber + secondNumber;
12 }
13
14 public void subtract(long firstNumber, long secondNumber) {
15 result = firstNumber - secondNumber;
16 }
17
18 public void multiply(float firstNumber, Float secondNumber) {
19 result = firstNumber * secondNumber;
20 }
21
22 }
And the form that causes (via waffle) some method invocations:
22 <form action="calculator.action" method="post">
23
24 <h3>Waffle example: Calculator</h3>
25
26 <div class="fieldRow">
27 <label for="firstNumber">FirstNumber:</label>
28 <input type="text" name="firstNumber" id="firstNumber" autocomplete="off"/>
29 <br style="clear:both"/>
30 </div>
31 <div class="fieldRow">
32 <label for="secondNumber">SecondNumber:</label>
33 <input type="text" name="secondNumber" id="secondNumber" autocomplete="off"/>
34 <br style="clear:both"/>
35 </div>
36
37 <div class="fieldRow">
38 <label for="result">Result:</label>
39 <input type="text" name="result" id="result" value="${action.result}" disabled="disabled" readonly="readonly"/>
40 <br style="clear:both"/>
41 </div>
42
43 <a href="javascript:fireMethod('add|{firstNumber}|{secondNumber}');">Add</a> |
44 <a href="javascript:fireMethod('subtract');">Subtract</a> |
45 <a href="javascript:fireMethod('multiply');">Multiply</a>
46
47 </form>
And the registrar (that needs to be implicated in a few extra lines in
web.xml) :
register("calculator", CalculatorAction.class);
Line 43 of the web page shows a single 'pragma' based linkeage, whereas
44 and 45 are Paranamer based (proving you can use both styles in you
want to in the same application. Clicking the 'Add' link for
this
example causes a POST invocation to the webapp with a URL of
/calculator.action and having the following form fields:
firstNumber=22
secondNumber=11
method=
add|{firstNumber}|{secondNumber}
That is assuming that you chose 22 and 11 as the numbers in the field.
For the two other actions (Subtract and Multiply, lines 44
and
45), which use Paranamer for the method signature assembly, with
/calculator.action as the URL:
firstNumber=11
secondNumber=22
method=
multiply
The colors hopefully help you see the linkage between page and method a
little easier.