Chariot Training Classes

Training Courses

I run Chariot's training and mentoring services. We provide training in AngularJS, HTML5, Spring, Hibernate, Maven, Scala, and more.

Chariot Education Services


Chariot Emerging Tech

Learn about upcoming technologies and trends from my colleagues at Chariot Solutions.


Chariot Conferences



Quizzo in Roo case of the Mondays. Or, how you can be a JPA doofus 

This morning I took a look at my schema, and started to cry. Well, not really, but in that way people say LOL, I say COL. Here was my original schema (click to view the picture in full resolution):

Wait, this guy knows JPA? Sure he does!

Now, I know some of you have my back here. You say, "look, JPA can be confusing, you have to work with it." The thing is, I wrote a bloody chapter on JPA relationships, I teach JPA, my head just wasn't in the game, OK?

Just kidding. You know by now I'm razzing you all...

Anyhoo, I didn't bother taking any time to pay attention to my relationships (sounds like somebody's going to have cold soup for dinner). Turns out, I was abusing my @JoinColumn and mappedBy settings.

How to do a bi-directional one-to-many relationship

Do it up, Rimp. Here's how. First off, you need to define your one-sided entity and allow it to contain your Set (don't get me started about alternative options for collection types, that'll take us all day):

public class Quiz {

    @Size(max = 200)
    private String title;

    @Size(max = 500)
    private String description;

    @OneToMany(mappedBy = "quiz",
        cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Set<Question> questions = new HashSet<Question>();


Now, I know we're all adults in here, so that's why I put the harder stuff in the cabinet. You see, there are several key items of critical information here:

  • The collection is of type Set, and I'm creating a prototype (for new entities before I save them) of the real type of HashSet. Don't assume they will be HashSet instances when you fetch them again, they likely could be proxies that hydrate when you touch them (wear coding gloves).
  • I've decided to use the cascade option to tell JPA to cascade changes to the questions if I persist or update (merge) the quiz.
  • The mappedBy element is all-important. This tells us that the property pointing back to our Quiz instance in the class named Question will be called quiz. This establishes what side owns the relationship. As one of my students once said, "if you see mappedBy, it means this class does NOT own the relationship." Good rule to live by.

Whew! I'm feeling weak and dizzy. A lot of information hiding in there. Let's look at the Question class for the other side of this thing:

public class Question {
  @JoinColumn(name = "quiz_id")
  private Quiz quiz;

Wow, that's it??? Huh. Ok, well erm let's give this a shake. This class is in charge of the relationship, meaning that if it is touched, it will handle the insert or update of the foreign key. So:

  • The quiz variable name matches the mappedBy element in the Quiz table. Think of this as the role of the relationship. You may use the same table twice with different roles (think sourceAccount, destinationAccount and you get the idea. They would each have different @OneToMany relationships with different mappedBy elements, thereby different roles and variables.
  • The foreign key column that handles the database relationship is called quiz_id, and so we'll get a table called Question with a foreign key in it called quiz_id

Easy, peasy! Now, if you look at the relationship between Question and Quiz in the image above, it looks like there are three tables. But in the one below, the relationships are all simplified. That's because I paid attention to @JoinColumn and mappedBy. Click the image to see the full copy:

Mmmm... Low fat data models. Delicious and 1/2 the tables of your normal schema.

What else did I change recently?

I also got the state machine 99% working, with just a hitch on the test that determines whether the quiz is over or not. I'll work on that one tonight, now that I can actually understand my data model without getting sick to my stomach.

I moved the QuizRunState tracking state into memory, as it was failing me. Oh, one more thing - don't assume that IntelliJ catches Java Language assert statements. I was guarding my code with assertions to catch any invalid states in the state machine. Turns out, Maven turns on assertion checking when testing but IntelliJ does not. I'm not talking about JUnit assertions, but the Java System assertion language statement, such as I use in this fragment of QuizRunStateMachineInMemory:

  public void startQuiz() {
    assert (runState == QuizRunState.NOT_STARTED);
    runState = QuizRunState.IN_PROGRESS;

Oh, it burns us baggins! To fix this, you edit your JUnit runner and add the -ea -esa flags to your vm settings. And, ladies and gentlemen, that was the reason I was getting errors in my Maven code that weren't showing up in IntelliJ. Just sayin'

See ya tomorrow (or maybe later tonight).


Quizzo Saturday - testing web flows

GitHub commit URLs: 82add3e1e23eee8b84058c12fcd6ff211f70096e and more importantly, 4cfed580c3404e61d501ac4ee0182c294b1b0b89

Ok, this is kind of a tangent. But I wanted to really debug the flow logic for these interactions, and better understand the flow logic itself before I bother to write up nice looking views.

Test that our flow starts with the correct state

I started with this first step, which is pretty easy to test:

<var class="" name="teamSetupForm"/>

<view-state id="register-team" view="playQuizzo/register-team"
    <transition on="continue" 
                bind="true" validate="true"/>

This state fills in a portion of the teamSetupForm flow-scoped variable. How do we test this? Somewhat easily. First, we start by building a test that is a subclass of AbstractXmlFlowExecutionTests:

public class QuizzoFlowTest extends AbstractXmlFlowExecutionTests {

  protected FlowDefinitionResource getResource(
               FlowDefinitionResourceFactory resourceFactory) {

    return resourceFactory.

Next, we have to build a method to expose a stub version of our Web Flow Spring Bean, the QuizzoFlowManager. It's referred to in the rest of the flow as quizzoFlowManager. This stub will replace our Spring Bean, and will provide access to any methods the flow calls. The flow execution engine may throw errors if it looks for this bean while parsing the form. So, we add this method to the test:

protected void configureFlowBuilderContext(
               MockFlowBuilderContext builderContext) {

  StubQuizzoFlowManager stubQuizzoFlowManager = 
                        new StubQuizzoFlowManager();


This method is called once we execute any flow start or resume methods in our mock flow engine.

Writing a flow test

Consider the test code below:

public void testStartFlow() {
  MutableAttributeMap map = new LocalAttributeMap();
  MockExternalContext context = new MockExternalContext();
  startFlow(map, context);
  TeamSetupForm form = (TeamSetupForm) getFlowScope().get("teamSetupForm");

The test does the following things:

  • Sets up a attribute map, required for starting a flow. This is just a property map.
  • Builds a fake Flow context, also required when launching a flow.
  • Calls the base test class's startFlow method, which launches the flow.
  • Checks to make sure that the flow is waiting on the register-team view state.
  • Checks to make sure the Web Flow engine creates the variable, teamSetupForm in the var webflow tag.
  • Checks to make sure the form is not null.

But what about checking events? For that, we'll push a "continue" event, and set the values that the form would have submitted in our Form bean:

public void testSubmitTeamName() {
  MockExternalContext context = new MockExternalContext();

      createTeamSetupForm("The Jets", "When you're a Jet you're a Jet"));


In this test, we start with the flow sitting on the register-team state. Since Web Flow is not running any states before our unit test, we have to create our teamSetupForm ourselves, and set the value of it using a helper method to include the team name and team message.

We then tell the context to send the continue event, and resume our flow. We check once this completes to make sure we are now sitting on the register-team-members state.

A more complex example

Now we are going to test the next state and its transition to the following state using continue:

<view-state id="register-team-members" view="playQuizzo/register-team-members"

  <transition on="continue" to="ready-to-play" bind="true" validate="true">
      <evaluate expression="quizzoFlowManager.saveTeamData(flowRequestContext)"/>
  <transition on="add-team-member"/>
  <transition on="remove-team-member"/>
  <transition on="back" to="register-team"/>

<action-state id="ready-to-play">
  <evaluate expression="quizzoFlowManager.pollReady(flowRequestContext)"/>
  <transition on="yes" to="play-round"/>
  <transition on="poll" to="poll"/>

You may think this test executes just fine:

public void testSubmitTeamMembers() {

  MockExternalContext context = new MockExternalContext();
      createTeamSetupForm("The Jets",
              "When you're a Jet you're a Jet",
      "Ice", "Action", "Baby John", "Tiger", "Joyboy"));


But it fails on the state assertion. It states that the state is actually play-round. How can this be?

Action States

This is because we're using an action state from our web flow. Action states do not wait on anything. They immediately execute their evaluations, and take action from their responses. I knew this when building the flow, but scanned by it when writing the test. Ugh.

How did I figure this out? You'd think by closely reading the ready-to-play state definition, but no... Instead, I amped up the logging for the webflow framework by setting this entry in

This rewarded me with a great amount of useful detail:

2012-02-25 12:19:47,032 [main] DEBUG org.springframework.webflow.engine.impl.FlowExecutionImplFactory - Creating new execution of 'flow'
2012-02-25 12:19:47,047 [main] DEBUG org.springframework.webflow.engine.impl.FlowExecutionImpl - Resuming in org.springframework.webflow.test.MockExternalContext@1494cb8b
2012-02-25 12:19:47,054 [main] DEBUG org.springframework.webflow.engine.Flow - Restoring [FlowVariable@3209fa8f name = 'teamSetupForm', valueFactory = [BeanFactoryVariableValueFactory@2d20dbf3 type = TeamSetupForm]]
2012-02-25 12:19:47,072 [main] DEBUG org.springframework.webflow.engine.ViewState - Event 'continue' returned from view [MockViewFactoryCreator.MockView@3e0d1329 viewId = 'playQuizzo/register-team-members']
2012-02-25 12:19:47,074 [main] DEBUG org.springframework.webflow.execution.ActionExecutor - Executing [EvaluateAction@2326a29c expression = quizzoFlowManager.saveTeamData(flowRequestContext), resultExpression = [null]]
2012-02-25 12:19:47,074 [main] DEBUG org.springframework.webflow.execution.AnnotatedAction - Putting action execution attributes map[[empty]]
2012-02-25 12:19:47,084 [main] DEBUG org.springframework.webflow.execution.ActionExecutor - Finished executing [EvaluateAction@2326a29c expression = quizzoFlowManager.saveTeamData(flowRequestContext), resultExpression = [null]]; result = success
2012-02-25 12:19:47,085 [main] DEBUG org.springframework.webflow.engine.Transition - Executing [Transition@3a4c5b4 on = continue, to = ready-to-play]
2012-02-25 12:19:47,085 [main] DEBUG org.springframework.webflow.engine.Transition - Exiting state 'register-team-members'
2012-02-25 12:19:47,086 [main] DEBUG org.springframework.webflow.engine.ActionState - Entering state 'ready-to-play' of flow 'flow'
2012-02-25 12:19:47,086 [main] DEBUG org.springframework.webflow.execution.ActionExecutor - Executing [EvaluateAction@36afae4a expression = quizzoFlowManager.pollReady(flowRequestContext), resultExpression = [null]]
2012-02-25 12:19:47,086 [main] DEBUG org.springframework.webflow.execution.AnnotatedAction - Putting action execution attributes map[[empty]]
2012-02-25 12:19:47,087 [main] DEBUG org.springframework.webflow.execution.AnnotatedAction - Clearing action execution attributes map[[empty]]
2012-02-25 12:19:47,087 [main] DEBUG org.springframework.webflow.execution.ActionExecutor - Finished executing [EvaluateAction@36afae4a expression = quizzoFlowManager.pollReady(flowRequestContext), resultExpression = [null]]; result = yes
2012-02-25 12:19:47,088 [main] DEBUG org.springframework.webflow.engine.Transition - Executing [Transition@47db9852 on = yes, to = play-round]
2012-02-25 12:19:47,088 [main] DEBUG org.springframework.webflow.engine.Transition - Exiting state 'ready-to-play'
2012-02-25 12:19:47,088 [main] DEBUG org.springframework.webflow.engine.ViewState - Entering state 'play-round' of flow 'flow'
2012-02-25 12:19:47,088 [main] DEBUG org.springframework.webflow.execution.ActionExecutor - Executing [EvaluateAction@21ed5459 expression = quizzoFlowManager.setupQuestionAndChoices(flowRequestContext), resultExpression = [null]]
2012-02-25 12:19:47,089 [main] DEBUG org.springframework.webflow.execution.AnnotatedAction - Putting action execution attributes map[[empty]]
2012-02-25 12:19:47,090 [main] DEBUG org.springframework.webflow.execution.AnnotatedAction - Clearing action execution attributes map[[empty]]
2012-02-25 12:19:47,090 [main] DEBUG org.springframework.webflow.execution.ActionExecutor - Finished executing [EvaluateAction@21ed5459 expression = quizzoFlowManager.setupQuestionAndChoices(flowRequestContext), resultExpression = [null]]; result = success
2012-02-25 12:19:47,091 [main] DEBUG org.springframework.webflow.engine.impl.FlowExecutionImpl - Assigned key 1
2012-02-25 12:19:47,091 [main] DEBUG org.springframework.webflow.engine.ViewState - Rendering + [MockViewFactoryCreator.MockView@643cb075 viewId = 'playQuizzo/play-round']
2012-02-25 12:19:47,092 [main] DEBUG org.springframework.webflow.engine.ViewState -   Flash scope = map[[empty]]
2012-02-25 12:19:47,092 [main] DEBUG org.springframework.webflow.engine.ViewState -   Messages = [DefaultMessageContext@4c6504bc sourceMessages = map[[null] -> list[[empty]]]]
2012-02-25 12:19:47,092 [main] DEBUG org.springframework.webflow.engine.Transition - Completed transition execution.  As a result, the new state is 'play-round' in flow 'flow'
2012-02-25 12:19:47,093 [main] DEBUG org.springframework.webflow.engine.Transition - Completed transition execution.  As a result, the new state is 'play-round' in flow 'flow'

If you spend time reading this, you'll see two flow state executions - one for the view state, and one for the action state. Our stub class returns "yes" from our transition in the poller state, and so we move to the next view state, play-round


Testing in WebFlow is rather difficult, because of the number of mock objects, the complexity of flow logic, and the fact that it's in XML, which is not compiled and therefore really requires tests. But is is worth it, as long as you're not using this as an excuse to test your beans themselves. You should test those either in unit or Spring integration tests. My assertions are mostly around making sure we submitted the right events to trigger the right view states.

Next I'll be wiring up some pages to these flow view states, and starting to really get the processing going. I'm also going to start writing an admin page to control the game itself and provide an audience view.


TGIF - Ok, last Friday Post - Spring Data JPA Makes it Sweeter

Now that we have our service and repository layers, let's not give people too much rope to hang themselves. Let's get rid of the Active Record model.

To do this, change the annotation from @RooJpaActiveRecord to @RooJpaEntity:

public class Team {

Now, watch Roo re-factor the configuration once we re-run the shell:

(create-repositories-and-services)⚡ [130] % roo                                                                                                  ~/git-repositories/quizzo
    ____  ____  ____  
   / __ \/ __ \/ __ \ 
  / /_/ / / / / / / / 
 / _, _/ /_/ / /_/ /  
/_/ |_|\____/\____/    1.2.1.RELEASE [rev 6eae723]

Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
Deleted SRC_MAIN_JAVA/com/chariot/games/quizzo/model/Team_Roo_Configurable.aj - 
  not required for governor
Deleted SRC_MAIN_JAVA/com/chariot/games/quizzo/model/Team_Roo_Jpa_ActiveRecord.aj - 
  not required for governor

Pretty nifty, right? Just make sure to fix-up any classes that needed Active Record. I had two of them:

  • One place where I persisted the team and team members in the webflow service.
  • Another place in the state machine where I use Team's static entityManager() method to access the Jpa Entity Manager.

Two easy fixes.

First, removing the ActiveRecord code from the webflow method:

  // inject the service:
  private TeamService teamService;
  // change from
  // to

Now we can actually test our webflow and mock the service layer. YAY!

Single Responsibility Principal...

This lump of code is like an extension cord between the browser and the database... Let's refactor it and provide it in a TeamService method, and inject that service call into our state machine.

The original code:

public Map<String, BigDecimal> getScores() {
  Map<String, BigDecimal> scores = new HashMap<String, BigDecimal>();

  Query query = Team.entityManager().createQuery("select t from team " +
      "t where = :id", Team.class).setParameter("id", quizRun.getId());
  List<Team> teams = query.getResultList();
  Iterator<Team> itTeams = teams.iterator();
  while (itTeams.hasNext()) {
    Team team =;
    scores.put(team.getName(), team.calculateTotalScore());
  return scores;

First, create a Spring Data JPA Repository interface method to handle what was our entity manager query. Add the highlighted lines to the Repository interface.

@RooJpaRepository(domainType = Team.class)
public interface TeamRepository {

  @Query("select t from Team t where = ?1")
  public List<Team> teamsByQuizRun(Long quizRunId);

Yep, Spring Data JPA is super cool. Check with our own Gordon Dickens - he has two blog posts you'd like to read if you want to know more about it.

Now, on to writing the new service method. We'll make it transactional and also read only:

// TeamService method:
public Map<String, BigDecimal> calcScoresByQuizRun(Long quizRunId);

// TeamServiceBean implementation:
@Transactional(readOnly = true)
public Map<String, BigDecimal> calcScoresByQuizRun(Long quizRunId) {

  Map<String, BigDecimal> scores = new HashMap<String, BigDecimal>();
  List<Team> teams = teamRepository.teamsByQuizRun(quizRunId);
  Iterator<Team> itTeams = teams.iterator();
  while (itTeams.hasNext()) {
    Team team =;
    scores.put(team.getName(), team.calculateTotalScore());
  return scores;

AND... Our call from the QuizRunStateMachineInMemory bean, which keeps track of state and lets us access the scores:

public Map<String, BigDecimal> getScores() {
  return teamService.calcScoresByQuizRun(quizRun.getId());
  • Note: even better- you can do this with one bit of logic - create a GROUP BY query in the Spring Data JPA method, and eliminate the middle tier. Adding to my refactoring list (broken windows!).

Now we've focused on responsibilities dealt with across this refactor:

  • QuizRunStateMachineInMemory - delivers information such as scores to web flows
  • TeamService - focuses on providing a calculation of scores, regardless of what datasource they use
  • TeamRepository - fetches teams from a JPA-backed data source

There. Now we've separated concerns, modularized our code a bit, and made it all much better to deal with.

Why not all in one heap?

Well, every framework looks great at first. You can just "get things done, quickly." The problem is, as you add developers, logic, fixes, complexity and the rest, it becomes a massive heap of code, with no visible organizing principles.

Final word (for this blog post)

Hey, let's flatten a Roo ActiveRecord finder into three lines!

// from roo's generated finder:

privileged aspect Answer_Roo_Finder {
    public static TypedQuery<Answer> Answer.findAnswersByTeamAndQuestion(Team team, Question question) {
        if (team == null) throw new IllegalArgumentException("The team argument is required");
        if (question == null) throw new IllegalArgumentException("The question argument is required");
        EntityManager em = Answer.entityManager();
        TypedQuery<Answer> q = em.createQuery("SELECT o FROM Answer AS o WHERE = :team AND o.question = :question", Answer.class);
        q.setParameter("team", team);
        q.setParameter("question", question);
        return q;

// to this:

@RooJpaRepository(domainType = Answer.class)
public interface AnswerRepository {
  @Query("SELECT a FROM Answer AS a WHERE = ?1 AND = ?2")
  public List<Answer> getAnswersByTeamIdAndQuestionId(Long teamId, Long questionId);

Ain't that sweet? Next post (unless I get derailed) on to testing the web flow methods.


Quizzo Friday - Goin' all layered on the darn thing

I'm currently working on a somewhat complex, ajax-based web flow. See commit 505fbe7989f62003a4188a4baab5b85cc31077fb for the additional methods and constructs. It's not working yet, so I figured I'd be a good little boy and write tests.

Now, I could be Mr. Smarty-pants and work with the models directly, and I've been doing so. However, here's where that breaks down - when I want to do some more involved application development, and want to try some web-flow tests using the WebFlow mock system, and need to mock the entity layer. That's just not so easy.

The challenge

Ok, take a look at what I'm up against here (click the image to see the fragment of the webflow, courtesy of IntelliJ's great WebFlow editor).
I have a section of the web flow that registers a new user. Two steps are currently involved, one with the team name, the second with a list of members (and this one is not yet working so don't bother reviewing it...)

I'll want to test the method being guarded by the exit, which is defined this way in the web flow:

<transition on="continue" to="ready-to-play">
  <evaluate expression="quizzoFlowManager.saveTeamData(flowRequestContext)"/>

The method in ~.web.flow.QuizzoFlowManagerBean looks like this currently:

  public Event saveTeamData(RequestContext flowRequestContext) throws FlowException {
    TeamSetupForm teamSetupForm = 

    Team team = new Team();

    Iterator<String> memberNamesIterator = 

    while (memberNamesIterator.hasNext()) {
      String teamMemberName =;
      TeamMember member = new TeamMember();

    flowRequestContext.getFlowScope().put("team", team);
    return success();

This is web-flow cruft. It's kind of like controller code, and it's defined in a Spring Bean that lives as a web-layer module. There are several problems with this:

  • It's doing persistence in a web-tier object
  • I don't want to make a web-tier object @Transactional
  • If I'm writing tests, how do I mock the entity layer without a lot of headache?

In thinking of how to express a test against this logic, I'm struck with how complex the test needs to be. It's tough enough to set up the Web Flow layer with the appropriate testing. But to then have to do some magic (see this post on @MockStaticEntityMethods - it hurts us, Baggins!).

I consider a good test to be documentation of the use-case or exercising of the code in question. That's what it should be. I'm sensing coupling here to both the web layer AND the data layer. Not so good, in my feeling. Although it's nice to have model objects and throw around Active Record calls everywhere for prototyping, I think this is where it falls down, in testing without being able to mock a service or repository layer cleanly.

Going all Repository on it

Ok, so how do I set up a repository for each bean? Easy-peasy.

repository jpa --entity ~.model.Answer        --interface ~.db.AnswerRepository
repository jpa --entity ~.model.Choice        --interface ~.db.ChoiceRepository
repository jpa --entity ~.model.Question      --interface ~.db.QuestionRepository
repository jpa --entity ~.model.Quiz          --interface ~.db.QuizRepository
repository jpa --entity ~.model.QuizRun       --interface ~.db.QuizRunRepository
repository jpa --entity ~.model.Team          --interface ~.db.TeamRepository
repository jpa --entity ~.model.TeamMember    --interface ~.db.TeamMemberRepository

Forgive me if my format looks a little odd - I used TextMate (my favorite Mac editor in the whole wide world) to manipulate the text using column pasting.

Now, I have a repository layer. I can do the same thing to add a service layer, but it needs a little more gusto (line breaks are for readability, it doesn't fit on one line in the blog):

service --entity ~.model.Answer --interface ~.service.AnswerService 
         --class ~.service.AnswerServiceBean
service --entity ~.model.Choice        --interface ~.service.ChoiceService
        --class ~.service.ChoiceServiceBean
service --entity ~.model.Question      --interface ~.service.QuestionService
      --class ~.service.QuestionServiceBean
service --entity ~.model.Quiz          --interface ~.service.QuizService
          --class ~.service.QuizServiceBean
service --entity ~.model.QuizRun       --interface ~.service.QuizRunService
       --class ~.service.QuizRunServiceBean
service --entity ~.model.Team          --interface ~.service.TeamService
          --class ~.service.TeamServiceBean
service --entity ~.model.TeamMember    --interface ~.service.TeamMemberService
    --class ~.service.TeamMemberServiceBean

Now, I have a true repository-and-service layer for my system. My controllers and integration tests automatically convert to using the services and repositories once they exist:

@RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String TeamController.create(...) {
  if (bindingResult.hasErrors()) {
    populateEditForm(uiModel, team);
    return "admin/teams/create";
  return "redirect:/admin/teams/" ...

It is special, isn't it. Next up, we'll show you how to unit test the logic in our web flow method.


Wednesday / Thursday Quizzo - flowin' it

Ok, most of my time in the last two days was non-quizzo related. Well, I should say non-business logic quizzo related. See, I was chasing my tail around the integration tests for the state of the quiz, which I've set up with a facade Spring Bean. Here's my interface:

public interface QuizRunStateMachine {
  void startQuiz(Long quizId, String text);
  boolean nextQuestion();
  Map<String, BigDecimal> getScores();
  Long getCurrentQuestionId();
  boolean submitAnswer(Team team, Answer answer);
  void endQuiz();
  QuizRun getQuizRun();

When I test the implementation of this state machine, which flips various bits in my database and keeps track of the current state, it works fine within IntelliJ (my IDE weapon of choice). However, when I use the maven test process, all tests fail due to the assertions coded within the bean. Grr.

I have no answer for that...

See above.

Anyhoo... Web flow, anyone?

Roo makes setting up the web flow engine easy. You just issue this simple command:

roo> web flow setup --flowName playQuizzo

The command sets up Web Flow, putting the flow itself in the WEB-INF/views/playQuizzo directory.

This blog entry lays out the beginning of using this strategy to implement a quiz player interface using web flow. It's incoherent a bit, as I'm sort of live-blogging this, so at some point I may go back and clean it up. But for now, hopefully it will serve as a helpful guide.

The flow

Here is a simple web flow (so far) that I've put together to handle the quiz flow:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flow xmlns="" xmlns:xsi=""

  <var class="" 

  <view-state id="register-team" 
    <transition on="continue" to="register-team-members" 
       bind="true" validate="true">
      <evaluate expression="quizzoFlowManager.debug(flowRequestContext)"/>

  <view-state id="register-team-members" 
    <transition on="continue" to="ready-to-play"/>
    <transition on="add-team-member"/>
    <transition on="remove-team-member"/>
    <transition on="back" to="register-team"/>

  <view-state id="ready-to-play" view="playQuizzo/ready-to-play">   
    <transition on="go" to="play-round">

  <view-state id="play-round" view="playQuizzo/play-round">    
    <transition on="submit-answer" to="play-round"/>
    <transition on="finish" to="game-over"/>

  <end-state id="game-over" view="playQuizzo/game-over"/>


This web flow is relatively simple- it requires the users to register their teams and team members, then keeps presenting the current question from the quiz run state machine, and as the submissions progress, the users keep submitting answers for each question, etc...

I haven't worked all of this out yet, and as I'm writing this blog post I'm about to commit at least a lame beginning to the scripts, but you get the idea.

Building our form views

Ok, so I have a love-hate relationship with the web tier of Roo. For simple cases, if you don't go off the rails (couldn't resist), it works fine. However, if you want to free-style it, maybe such as set up non-RESTful views such as web flows, it breaks down because of the implicit conventions (specifically the form has to be RESTful in some way, includes a primary key, optional version, and most importantly, those dang Submit buttons.

I'm using Web Flow for the quiz takers. It makes sense to me (so far) that the quiz manager will control the flow using a specific set of protected pages only he can get to, which interact with the manager methods of my state machine (starting a quiz, advancing to the next question, etc).

However, the users will be walking through a directed web flow. The flow will have various actions, and they will be whatever I want them to be - bottom line, I have to break with Roo conventions. So I'm setting up my own Roo tags for a generic form, button grouping, and buttons.

The Form

I will update this as I go along, but here is my current generic "form" tag, which I place alongside form:create and others as form:form:

<jsp:root xmlns:c="" 
          xmlns:spring="" version="2.0">

    <jsp:output omit-xml-declaration="yes"/>


    <c:set var="enctype" value="application/x-www-form-urlencoded"/>

    <c:if test="${multipart}">
        <c:set var="enctype" value="multipart/form-data"/>

    <c:if test="${empty action}">
        <spring:url value="${path}" var="action"/>

    <c:if test="${empty path}">
        <spring:url value="/playQuizzo" var="${path}"/>

    <c:if test="${empty label}">
        <spring:message var="label" code="${labelCode}"/>

    <util:panel id="${id}" title="${label}" openPane="${openPane}">
        <form:form method="POST" action="${path}"
            <form:errors cssClass="errors" delimiter="&lt;p/&gt;"/>


I have the when and otherwise in there to handle the case where we're submitting back to ourselves (web flow) and otherwise, if a path was given, submit to that path.

Anyhoo... the button group

Ok, so I also made a buttons tag to group buttons together, because on the Roo forms the singluar button was wrapped in a styled div:

<jsp:root ...>
  <jsp:output omit-xml-declaration="yes"/>
  <div class="submit" id="form_submit">
      <jsp:doBody />

Really just a wrapper div, you know...

The button tag

Then, I put together a button tag which configures buttons for the form. You can add as many as you want. This is in tags/form/field/button.tagx:

   xmlns:jsp="" version="2.0">
    <jsp:output omit-xml-declaration="yes"/>


    <c:if test="${empty text}">
        <spring:message code="label_${fn:toLowerCase(fn:substringAfter(id,'_'))}" var="label" htmlEscape="false"/>

    <c:set var="sec_field">
        <spring:escapeBody javaScriptEscape="true">${field}</spring:escapeBody>

    <c:if test="${empty validate or validate}">

    <input id="_${sec_id}_id" type="submit" value="${text}" name="${value}"/>

The gist of this tag is to create the same validator declaration on the buttons (as long as they need validation) as before. Note that I don't turn my buttons into Dojo buttons. Neither does the Roo team. I guess they felt that the standard submit buttons were OK. My goal here is to make the library conform, so any stylesheet manipulation I do will work equally well for scaffolded forms as well as my new ones.

Using the forms library, or where I got cranky

Ok, you see now my goal was to make life easy for web flow and non-scaffolded forms developers. Also I wanted to extend what we already had - not dip into the Spring MVC form tag libraries for fields, but use the Roo ones.

And that's where the fun stopped for a bit.

Label conventions

Let me lay this out, as I've tried to explain in Roo in Action but have more space here. The conventions that I am aware of for forms, fields, and other things are not well understood even by me. For exmample, if I plop a <fields:input%gt; tag down, and want to set the label, I have to remember to do this:

  • Set the label up in
  • Prefix the message id itself in the properties file with label_
  • Use the label without the label_ prefix in the JSPX page
  • Use the labelCode attribute rather than label
  • Most cryptically: use _field_id as the id of the form fields, as opposed to the field id, as the tag will write an HTML tag with the un-underscored field name and id, and a Dojo dijit for the field with the underscored name. Otherwise, your field will not be submitted

I logged a few JIRA issues as suggestions to implement this tag set and also to make overall non-scaffolded ui more kind to the developer. We'll see how this evolves over time.

Using the tag library:

Ok, so that means I have something like this in my JSPX file:

      <fields:input id="_name" field="name"
              required="true" min="1" max="80" />
          <fields:button id="continue" text="Continue" 

and this in my properties file:

label_webflow_playquizzo_register_team_name_field_label=Team Name

That took me a bit of time to unwind as I was writing my form, but in the end, it made it more concise. And I forced myself to locallize. Well, almost completely.

Next up, I complete the web flow and get the state machine going.

More later...

Page 1 ... 7 8 9 10 11 ... 37 Next 5 Entries »