Fork me on GitHub

My first WoOF application

This tutorial walks you through creating and running your first Web on OfficeFloor (WoOF) application.

Setup

The following are the pre-requisite setup before working through the tutorial:

  1. Install Maven
  2. Install Eclipse
  3. Install the Maven plug-in into Eclipse
  4. Install the OfficeFloor plug-in into Eclipse

Creating the WoOF project

The create a WoOF project use the Maven WoOF archetype. Run the following within an empty directory:

    mvn archetype:generate -DarchetypeGroupId=net.officefloor.maven -DarchetypeArtifactId=woof-archetype

Select net.officefloor.maven:woof-archetype (if not already selected) and provide the Maven configuration parameters. The tutorial uses the following parameters:

groupId=test.group
artifactId=WoofArchetypeResult
version=0.1-SNAPSHOT
package=net.officefloor.test

Once complete there should now be a directory created by the name of the artifactId.

Change into the created directory and run the following to build the project:

    mvn install

Running the WoOF project from Maven

Once the project is built, run the following within the project directory to start the application:

    mvn woof:run

The following may be needed to add to your maven settings.xml file to default the group:

  <pluginGroups>
    <pluginGroup>net.officefloor.maven</pluginGroup>
  </pluginGroups>

The application will now be available at http://localhost:7878/static.woof and look as follows:

WoOF Archetype Static Page Screen Shot

To stop the application, run:

    mvn woof:stop

Running the above commands will actually start two processes. The first process is the OfficeBuilding while the second is the OfficeFloor WoOF web application. Rather than having a single process which hosts each application, OfficeFloor has a central process (OfficeBuilding) which spawns each application (OfficeFloor) to run in its own process. This central control process, OfficeBuilding, will expose JMX beans for controlling the OfficeFloor instances on port 13778. The above command will ensure OfficeBuilding is running and then start the WoOF web application.

Running the WoOF project within a JEE container

Jetty provides a Maven plug-in for running a WebApp project within a JEE (Servlet) container.

Use the following command within the project directory to run:

    mvn org.mortbay.jetty:jetty-maven-plugin:run

After running the above command, the WoOF application will be available at: http://localhost:18080/static.woof

Importing the WoOF project into Eclipse

Open Eclipse and import the created directory as an existing Maven project.

Using the above configuration the following should be the project structure within Eclipse.

WoOF Project Structure

For those familiar with Maven web projects this should be a very familiar structure:

  • src/main/java : contains the java code
  • src/main/resources : contains resources to go on the class path
  • src/test/java : contains the unit test code
  • src/main/webapp : contains the web resources
  • pom.xml : provides details of the project and is packaged as a war

While WoOF provides a more flexible structure it does not want to reinvent the wheel and re-uses the WAR structure.

There are however some minor differences to accommodate the flexibility of WoOF.

Difference Reason
Configuration of the WoOF application is via the application.woof file WoOF uses graphical configuration. See below.
Web resources for a WoOF template following the naming convention [name].woof.[extension] WoOF provides non-obtrusive instrumentation of the templates so that the raw template HTML files can be displayed in a browser. This allows WYSIWYG web development tools to develop the web pages and fast turn around times by rendering the raw HTML file within a web browser. Placing these files with the web resources directory allows relative paths to pick up CSS, images, etc when opened within a web browser.

Running the WoOF project from within Eclipse

To run the WoOF project from within Eclipse, right click on the application.woof file as Run as... WoOF.

This will bring up the development console and have your application running. Use the console to open the web page to the URI of interest.

WoOF graphical configuration

WoOF is configured through the application.woof file. Opening this file with the OfficeFloor Eclipse Plug-in (i.e. WoOF Editor) will provide the following graphical configuration for the application.

WoOF archetype project configuration.

The very simple configuration shows three web pages with sequential navigation.

  • static : example static HTML page (useful for static content and wireframing a prototype web application)
  • form : example dynamic form to enter and validate information
  • ria : example Rich Internet Application functionality that makes a simple AJAX call to the server

There are various other configuration items that can be added by right clicking within the WoOF editor. Please see the other tutorials for further details.

HTML templating and Java server logic

The form page looks as follows:

WoOF Archetype Form Page Screen Shot

The following is the HTML for the form page.

<html>
<head>
	<title>Page with form submission</title>
	<link href="./css/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>

<p><img style="width: 10em" src="./images/OfficeFloorBannerImage.png" /></p>

<p>Form submission HTML page with dynamic content.</p>

<form action="#{processValues}" method="POST">
	<p>Name: <input type="text" name="name" value="${name}" />${nameIssue <span class="error">${message}</span> $}</p>
	<p>Age: <input type="text" name="age" value="${age}" />${ageIssue <span class="error">${message}</span> $}</p>
	<p><input type="submit" value="submit" /></p>
</form>

</body>
</html>

The instrumentation of HTML page is through the #{link}, #{bean ... $}, and ${property} tags that are mapped by name to methods on the following server POJO (plain old java object):

package net.officefloor.test.form;

import java.io.Serializable;
import net.officefloor.plugin.web.http.application.HttpParameters;
import net.officefloor.plugin.work.clazz.FlowInterface;

/**
 * Logic for the <code>form.woof.html</code>.
 */
public class FormLogic {

	@HttpParameters
	public static class Parameters implements Serializable {

		private String name;

		private Issue nameIssue;

		private String age;

		private Issue ageIssue;

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public Issue getNameIssue() {
			return nameIssue;
		}

		public void setNameIssue(Issue nameIssue) {
			this.nameIssue = nameIssue;
		}

		public String getAge() {
			return age;
		}

		public void setAge(String age) {
			this.age = age;
		}

		public Issue getAgeIssue() {
			return ageIssue;
		}

		public void setAgeIssue(Issue ageIssue) {
			this.ageIssue = ageIssue;
		}
	}

	public static class Issue {

		private String message;

		public Issue(String message) {
			this.message = message;
		}

		public String getMessage() {
			return this.message;
		}
	}

	@FlowInterface
	public static interface Flows {

		void complete();
	}

	/**
	 * Provides the {@link Parameters} for values to template rendering.
	 * 
	 * @param parameters
	 *            Either new {@link Parameters} or the {@link Parameters} from
	 *            form submission.
	 * @return {@link Parameters} for template values.
	 */
	public Parameters getTemplate(Parameters parameters) {
		return parameters;
	}

	/**
	 * Processes the submission of the form.
	 * 
	 * @param parameters
	 *            {@link Parameters} loaded with HTTP parameters values from
	 *            form submission.
	 * @param flows
	 *            {@link Flows} to control flow of navigation.
	 */
	public void processValues(Parameters parameters, Flows flows) {

		boolean isIssue = false;

		// Must have name
		String name = parameters.getName();
		if ((name == null) || (name.trim().length() == 0)) {
			parameters.setNameIssue(new Issue("Must provide name"));
			isIssue = true;
		}

		// Must have valid age
		String age = parameters.getAge();
		if ((age == null) || (age.trim().length() == 0)) {
			parameters.setAgeIssue(new Issue("Must provide age"));
			isIssue = true;
		} else {
			// Ensure number
			try {
				Integer.valueOf(age.trim());
			} catch (NumberFormatException ex) {
				parameters.setAgeIssue(new Issue("Age must be a number"));
				isIssue = true;
			}
		}

		// On issue, render page with details
		if (isIssue) {
			return;
		}

		/*
		 * TODO do some business logic with the values. May include further
		 * dependencies to this method such as a database connection for the
		 * business logic. See http://officefloor.net/tutorials for more
		 * details.
		 */

		// Navigate away from page
		flows.complete();
	}

}

Beyond a few annotations the logic class is straight forward Java.

Please see the other tutorials for explanation of the code and the further features available.

Unit testing the WoOF application

The following unit test shows the ease in which to start and stop the application for unit testing.

package net.officefloor.test;

import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.net.URL;

import net.officefloor.plugin.woof.WoofOfficeFloorSource;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * Runs application and ensures a page is available.
 */
public class RunApplicationTest {

	@Before
	public void runApplication() throws Exception {
		// Start the application
		WoofOfficeFloorSource.start();
	}

	@Test
	public void ensureApplicationAvailable() throws Exception {

		// Connect to application and obtain page
		URL url = new URL("http://localhost:7878/static.woof");
		Reader response = new InputStreamReader(url.openStream());
		StringWriter content = new StringWriter();
		for (int character = response.read(); character != -1; character = response
				.read()) {
			content.write(character);
		}

		// Ensure correct page
		Assert.assertTrue("Incorrect page",
				content.toString().contains("<title>Static Page</title>"));
	}

	@After
	public void stopApplication() throws Exception {
		// Stop the application
		WoofOfficeFloorSource.stop();
	}

}

Congratulations

Congratulations you have just created and run your first WoOF web application.

The next tutorial covers prototyping a web application with WoOF.