Reusable MVC with Htmleasy, resteasy and jsp

In previous post we create set up for multi-modular java project using gradle. Now we are going to explore the sample code behind ugly-web project and what is concept behind the sample in order some of you to use in your own project. Also in previous post we discuss why we are using Htmleasy, resteasy and jsp for our MVC instead of spring MVC. Last thing about ugly-web project is the configuration which can be found on my svn repo. Maybe in the future I will write post about configuration of Htmleasy, resteasy and jsp.

Now let’s start discussion about the sample code. I have code two projects in Spring MVC and I have notice a repeatable copy-paste pattern for handling GET and POST requests, which can be express with algorithms.

GET request algorithm:

step 1. Create new Model
step 2. Return corresponding view for the GET request, with the newly model

POST request algorithm:

step 1. Validate the model, which is created from http request
step 1.1. If model is not valid, return list of errors to the corresponding view
step 1.2 If model is valid, do business logic for successful post handling

I don’t say that your logic in GET and POST methods is similar, but in 80-90% of the time, your business logic can be express with these two algorithms and also implementation of these two simple algorithms is dependent from the frameworks you are using, but in the end you will have reusable behavior for GET and POST.

Our implementation is based on MVC and Template method pattern.

First our GenericModel class, which represents base class for all our Models

import java.util.ArrayList;
import java.util.List;

import org.ugly.interfaces.DomainEntity;
import org.ugly.service.facade.EJBServiceFacade;

import com.googlecode.htmleasy.playground.domain.ValidateResponse;

public abstract class GenericModel {

	protected List<String> errors;
	protected Object[] domainEntities;
	protected EJBServiceFacade bizz;

	protected GenericModel(EJBServiceFacade b, int numberOfEntities) {
		errors = new ArrayList<String>();
		domainEntities = new Object[numberOfEntities];
		this.bizz = b;
	}

	public GenericModel cloneModel(DomainEntity[] domainToClone) {
		domainEntities = null;
		domainEntities = new Object[domainToClone.length];

		for (int i = 0; i < domainToClone.length; i++) {
			this.domainEntities[i] = domainToClone[i].copyOf();
		}

		this.errors = new ArrayList<String>();
		return this;
	}

	public abstract GenericModel newModel();

	public abstract boolean validateModel();

	public abstract ValidateResponse ajaxValidator(Object... toBeValidate);

	public List<String> getErrors() {
		return errors;
	}

	public Object[] getDomains() {
		return domainEntities;
	}

}

We define three fields:

  • list of errors
  • array of domain objects
  • and facade for business methods.

These fields are protected because they will be used in sub-classes which are going to be derived from this GenericModel class. Array of domain objects creates more reusable solution, because we use the same entities for db and UI representation. If we want additional fields, we can add them at specific model class.

Methods:
We have constructor that is used by sub-classes, which creates empty error list, creates array of domain objects and initialize the business facade. Next method is cloneModel, which creates copy of the domain objects and empty list of errors.
Next two methods are abstract (a.k.a templates) and have their implementation is different for every model. Every model sub-class have different way of creating new model(newModel()) and validating that same model (validateModel()). Also, we have validating data from ajax request (ajaxValidator(Object… toBeValidate)). The last methods are just getters for errors and domain objects (these methods breaks the encapsulation but they are required by EL language used in jsp for data binding).

Now, lets look at concrete implementation of the generic model:

import org.ugly.entities.SignupDetails;
import org.ugly.service.facade.EJBServiceFacade;

import com.googlecode.htmleasy.playground.domain.ValidateResponse;

/** Simple POJO to store our view model. */
public class UserModel extends GenericModel {

	private Long count;

	public Long getCount() {
		return count;
	}

	public void setCount(Long count) {
		this.count = count;
	}

	public UserModel(EJBServiceFacade b) {
		super(b, 1);
	}

	@Override
	public GenericModel newModel() {
		this.domainEntities[0] = bizz.getAllSignupDetails().get(0);
		this.count = bizz.countSignupDetails();
		return this;
	}

	@Override
	public boolean validateModel() {
		SignupDetails domainToBeValidate = ((SignupDetails) domainEntities[0]);
		domainToBeValidate.validate(errors);
		ValidateResponse response = ajaxValidator(domainToBeValidate
				.getAjaxValidatorFields());

		if (!response.isValid()) {
			this.errors.add(response.getMessage());
		}

		return errors.size() == 0;
	}

	@Override
	public ValidateResponse ajaxValidator(Object... toBeValidate) {
		String username = toBeValidate[0].toString();
		if (username == null || username.length() == 0) {
			return new ValidateResponse(false, "Please enter a username.");
		} else if (username.startsWith("admin") || username.equals("john")) {
			return new ValidateResponse(false,
					"This username is already taken.");
		} else if (username.length() < 4) {
			return new ValidateResponse(false,
					"Usernames must be 4 or more letters.");
		} else if (username.contains(" ")) {
			return new ValidateResponse(false,
					"Usernames must not contain spaces.");
		}
		return ValidateResponse.VALID;
	}

}

We override all methods and we implemented specific logic for all of them. New model is created from the data fetch from database, we validate our model (every UI entity implements validation method) and we create ajax validator only for username.

Whole page:


<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@page import="com.googlecode.htmleasy.playground.UserModel"%>
<%@page import="com.googlecode.htmleasy.playground.UserSignup"%>

<html>
<head>
    <style type="text/css">
      #usernameMsg {color: red;}
    </style>
	<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
	<script  type="text/javascript">
		// User JQuery to wire up call to the AJAX username validate method
		$(function () {

			$("#username").keyup(function (e) {
				var $element = $(this);
				$.ajax({
					type: "POST",
					url: "/signup/validate_username",
					data: {"username" : $element.val()},
					success: function (response) {
							if (!response.valid) {
								$("#usernameMsg").text(response.message);
							} else {
								$("#usernameMsg").text("");
							}
						},
				});
			});

			// Select the sex based on the model value
			$("#sex").val("${model.domains[0].sex}");

		});
	</script>
</head>
<body>
	<c:out value="${pageContext.request.contextPath}" />
	<h1>New User Signup Form</h1>

	<%

		UserModel model = (UserModel) request.getAttribute("model");

		if (model.getErrors().size() > 0) {
			out.append("<div class='errorMessage'>");
			out.append("<ul>");
			for (String error: model.getErrors()) {
				out.append("<li>").append(error).append("</li>");
			}
			out.append("</ul>");
			out.append("</div>");
		}
	%>

	<form method="post" action="/signup">
	    <table>
		  <tr>
		    <td>Username:</td><td><input id="username" type="text" name="username" value="${model.domains[0].username}"/> <span id="usernameMsg"></span><td>
		  <tr>
		  <tr>
		    <td>Password:</td><td><input type="password" name="password" value="${model.domains[0].password}"/></td>
		  </tr>
		  <tr>
		    <td>Confirm Password:</td><td><input type="password" name="confirmPassword" value="${model.domains[0].confirmPassword}"/></td>
		  </tr>
		  <tr>
		    <td>Sex:</td>
		    <td>
				<select id="sex" name="sex">
					<option value="Unknown"></option>
					<option value="Male">Male</option>
					<option value="Female">Female</option>
				</select>
			</td>
		   </tr>
		   <tr>
		     <td colspan="2"><input type="checkbox" name="agreedLegal" value="true" /> I agree to the legal terms
		   </tr>
		   <tr>
		     <td colspan="2" style="padding-top: 1em;"><input type="submit"/></td>
		   </tr>
		</table>
	</form>
    <p>
    There are ${model.count} entities in DB.
    </p>
</body>
</html>

Part that we are interested:

<input id="username" type="text" name="username" value="${model.domains[0].username}"/>

As you can see we use EL expression ${model.domains[0].username}. model is default referring to model in htmleasy (this can be changed), domains[n] accessing n-th domain object and username is the property of our domain object. It’s interesting because we the type of object is discovered on runtime, so expression model.domains[i] (where i is i-th domain object) is static and this is very useful for copy-paste or find-replace 🙂
Ok, that for the model part, now let’s take a look at Controller part and see the big picture.

import org.ugly.interfaces.DomainEntity;
import org.ugly.service.facade.EJBServiceFacade;

import com.googlecode.htmleasy.View;

/**
 * @author gjorgji
 * 
 */
public abstract class GenericController<M extends GenericModel> {

	protected M model;
	protected String returnGet;
	protected String returnFailOnPost;

	protected EJBServiceFacade bizz;

	public View defaultGet() {
		return new View(returnGet, model.newModel());
	}

	public View defaultPost(DomainEntity[] httpDomainObject) {
		GenericModel m = (GenericModel) model.cloneModel(httpDomainObject);

		if (!m.validateModel()) {
			return new View(returnFailOnPost, m);
		}
		return successfullPostHandler();
	}

	protected abstract View successfullPostHandler();

}

As you can see from the code in GenericController we coded algorithms of GET/POST requests and we name methods default(Get/Post), because it’s default handling mechanism for GET/POST requests. There isn’t any explanation of method logic, because they are just coded algorithms previously explain. Of course, if your logic for handling GET/POST is different, then you can write your own logic.
Here is example of concrete controller

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import org.jboss.resteasy.annotations.Form;
import org.ugly.entities.SignupDetails;
import org.ugly.interfaces.DomainEntity;
import org.ugly.service.facade.EJBServiceFacade;

import com.googlecode.htmleasy.RedirectException;
import com.googlecode.htmleasy.View;
import com.googlecode.htmleasy.playground.domain.ValidateResponse;

@Path("/signup")
@RequestScoped
public class UserSignup extends GenericController<UserModel> {

	public UserSignup() {
		super();
		this.returnGet = "/WEB-INF/templates/playground/signup/form.jsp";
		this.returnFailOnPost = "/WEB-INF/templates/playground/signup/form.jsp";
	}

	@Inject
	public void setBizzFacade(EJBServiceFacade b) {
		this.bizz = b;
		this.model = new UserModel(b);
	}

	@GET
	public View showSignupForm() {
		return defaultGet();
	}

	@POST
	public View processSignup(@Form SignupDetails signupDetails) {
		return defaultPost(new DomainEntity[] { signupDetails });
	}

	@GET
	@Path("/thanks")
	public View showSignupThanks() {
		return new View("/WEB-INF/templates/playground/signup/thanks.jsp");
	}

	/**
	 * Validate a username server-side to ensure it's suitable for the signup
	 * process.
	 * 
	 * This method is exposed to the web view layer via AJAX as well as used
	 * directly in Java when processing the post.
	 * 
	 * Note: Of course in a real application some of the validation in this
	 * method would be done client-side, however some tasks such as the
	 * availability of a username can only be done server-side.
	 * 
	 * @param username
	 *            The username to validate.
	 * @return A response object containing the validation status and a message.
	 */
	@Path("/validate_username")
	@POST
	@Produces("application/json")
	public ValidateResponse usernameValidator(
			@FormParam("username") String username) {
		return model.ajaxValidator(new Object[] { username });
	}

	@Override
	protected View successfullPostHandler() {
		throw new RedirectException("/signup/thanks");
	}

}

Gradle, WildFly 8 with Eclipse

Hello World,
Searching for the web it’s hard to find a good ready to use initial project structure, so I made my own project set up. A little bit of copy paste, a little bit of research and some of it I learn from mistakes in the past. I call the project Ugly, because nothing is smooth when you combine more then one component-oriented software (a.k.a frameworks) in one project.
Project Structure (classical approach)

  • ugly-web, is for web presentation (a.k.a web pages)
  • ugly-ejb-services, is for ejb business components
  • ugly-dao-services, is for your dao objects
  • ugly-entities, is for your domain objects a.k.a database tables mapped in classes
  • ugly-common,  is for common classes used by all application layers
  • ugly-data-generator is for generating test data and also proving the correctness of your domain model

Gradle is a new build tool, which in couple of years will replace Maven as de-facto build tool.It’s easy to use even if you don’t know Groovy language (like me) and setup a project structure and start working 🙂
Whole build.gradle script

description = "Ugly project because awesome is too fucking mainstream"
apply from: 'http://www.tellurianring.com/projects/gradle-plugins/gradle-templates/apply.groovy'

allprojects {
	apply plugin: "java"
	apply plugin: "eclipse"
	apply plugin: 'eclipse-wtp'
	sourceCompatibility = 1.7
	targetCompatibility = 1.7
	version = '1.0'
	repositories {
		mavenCentral()
                maven{
			url "http://htmleasy-maven.googlecode.com/svn/trunk/"
		}
		mavenRepo name: 'jboss-nexus', url: "http://repository.jboss.org/nexus/content/groups/public/"
	}

	configurations {
	    provided
	}
	sourceSets {
	    main.compileClasspath += configurations.provided
	    test.compileClasspath += configurations.provided
	    test.runtimeClasspath += configurations.provided
	}
	eclipse {
	  classpath {
	    plusConfigurations += configurations.provided
	  }
	}

}

// Domain projects
project(":ugly-entities") {
	dependencies {
	  provided "org.hibernate:hibernate-core:4+"
	  provided "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1+"
	  provided "javax.validation:validation-api:1+"
	  provided "org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_1.1_spec:1+"
	  compile project(":ugly-common")
	}
}

project(":ugly-data-generator") {

	dependencies {
	  // Dependencies for all entities
	  compile project(":ugly-entities")
	  compile project(":ugly-dao-services")
	  compile "org.fluttercode.datafactory:datafactory:0.8"
	  compile "org.hibernate:hibernate-core:4+"
	  compile "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1+"
	  compile "javax.validation:validation-api:1+"
	  compile "org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_1.1_spec:1+"
	  compile "org.hibernate:hibernate-entitymanager:4+"
	  compile "postgresql:postgresql:9+"
	}

}
project(":ugly-common") {
	dependencies {
	  // Dependencies for all entities
	}
}

// EJB Projects
project(":ugly-ejb-services") {
	dependencies {
	  // Dependencies for ejb services
	  compile project(":ugly-dao-services")
	  provided "org.jboss.spec.javax.ejb:jboss-ejb-api_3.1_spec:1+"
	  provided "javax.enterprise:cdi-api:1+"
	  provided "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1+"
	}
}

project(":ugly-dao-services") {
	dependencies {
	  // Dependencies for daos
	  provided "org.hibernate:hibernate-core:4+"
	  provided "org.hibernate:hibernate-entitymanager:4+"
	  provided "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1+"
	  provided "postgresql:postgresql:9+"
	  provided "org.jboss.spec.javax.ejb:jboss-ejb-api_3.1_spec:1+"
	  provided "javax.enterprise:cdi-api:1+"
	  compile project(":ugly-entities")
	}

}
// WEB Projects
project(":ugly-web") {
	apply plugin: 'eclipse-wtp'
	apply plugin: 'war'

	eclipse {
	  wtp {
	    facet {
	      facet name: 'jst.java', version: '1.7'
	      facet name: 'jst.web', version: '3.1'
	    }
	  }
	}

	dependencies {
	  // Dependencies for web app
	  compile project(":ugly-ejb-services")
	  provided "org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_1.1_spec:1+"
	  provided "javax.enterprise:cdi-api:1+"
	  provided "org.jboss.spec.javax.ejb:jboss-ejb-api_3.1_spec:1+"
	  provided "org.jboss.resteasy:resteasy-jaxrs:3+"
	  provided "com.googlecode.htmleasy:htmleasy:0.7"
	  provided "javax.servlet:jstl:1+"
	  provided "jstl:jstl:1+"
	  provided "taglibs:standard:1+"
	  provided "javax.servlet:servlet-api:3+"
	  provided "javax.servlet:jsp-api:2+"

	  provided "org.hibernate:hibernate-core:4+"
	  provided "org.hibernate:hibernate-entitymanager:4+"
	  provided "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1+"

	}
}

How let examine the script step by step.
First we apply gradle plug-in for easy creating couple of projects like Java, Java Web, Scala, Groovy. It’s nice plug-in if you don’t want to use IDE support for creating projects

apply from: 'http://www.tellurianring.com/projects/gradle-plugins/gradle-templates/apply.groovy'

Next section is called allprojects and here we define all common properties for all projects. In this section we apply plug-ins for java, eclipse and eclipse-wtp. The last plug-in eclipse-wtp provides useful features for customizing the nature (Project Facets) of eclipse project. After that we override value on default properties, which in our case are important and need to set on every project. These properties are sourceCompatibility, targetCompatibility and version. There names are self-explanatory and in my case they are set to the latest java 1.7 and the version is for project version which is by default 1.0 🙂 The next thing we setup the repositories for dependency management and enable provided feature for jars to all projects. Provided isn’t available in Gradle by default, so we need to implement which is easy (if you Google currently). In configuration section, we declare provided then in sourceSets we added provided dependency to classpaths. This is only for java plug-in, which in most cases isn’t good because not everybody use text editors to develop java, most of developers use IDE, which in my case is Eclipse, so we append the same in eclipse plug-in. With this step we finished with building foundation for our ugly projects. Now it’s time to define them in ground-up fashion.
First project that we explore is ugly-common and its is share by all projects. The purpose of this project is to put classes which can be share from all project like Convertors, Utilities, Exceptions etc. This project in my case doesn’t have any jar dependency, but when your project grow in size it’s nice to have some utility jars like Apache Common or other similar jars.

Next project is ugly-entities which serves as separate logical unit for our domain objects. The dependency javax.ws.rs is for rs bindings like @Form and @FormParam, because our domain object will be reused in web-ui.
Project ugly-dao-services contains dao services, which are part from dao layer and these services execute database operations.
Project ugly-ejb-services contains ejb services and project ugly-web contains web UI for the application.In our case for MVC pattern we use resteasy (Controler), htmleasy (View dispatcher) and jsp (View renderer).

In most cases, developers will use Spring MVC, but if you don’t use Spring eco-system like in my case, adding Spring MVC to your project will add half of spring core projects :). In order to emulate MVC pattern (use similar clean programming API) like in spring MVC, we only need htmleasy as View dispatcher, because other things are provided by wildfly standard distribution. Even without htmleasy we can emulate spring MVC programming api, but in that case we need to make 5-6 classes, which is already done by htmleasy (only 20k in size).

At last, we need to start coding our ugly project in eclipse, so for that purpose we have four command, which you need to execute in order to import gradle project to eclipse

  • gradle clean
  • gradle build
  • gradle cleanEclipse
  • gradle eclipse

After this will import project to eclipse, as gradle projects as shown in the picture below
eclipseGradleImport

Here is the link to svn source repository
Ugly project svn repo
In next posts we will explore ugly sub-projects in more detail way and there are some interesting concepts for reducing complexity of the building software.