Reasons My Code Is Crying

.java, .js, .* - by Pieter Grobler

Creating an Application With Wildfly (Java EE REST) and backbone.js - Part 2

In my previous post, we have set up a Wildfly instance to host our REST services. In this post, we proceed to implement the actual RESTful services for our todo list application.

As a side note, why are we not just using node.js for this back-end? Well, funny you should ask that. The reason is that we are simulating an application that requires mission-critical transactional integrity, among other standard enterprise features. I do strongly believe in the power of Java EE 7 to deliver all this - it is surprisingly light-weight for this level of robustness and encapsulates all the enterprise complexity, leaving us to concentrate on the business logic. Also, as a responsible developer, I never create any application escaping the power of our lord, Eric Evans and his wisdom of the domain-driven application. Therefore, you will notice that I create a couple of classes, probably more than necessary to simply achieve the required functionality, aiming to decouple the domain from the rest of the application.

But of course, I digress, and I’ll make up for it by presenting our entity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

package com.pietergrobler.todo.model;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
public class ToDoTask implements Serializable
{

  private static final long serialVersionUID = 7296051067463179978L;

  @Id
  @GeneratedValue
  private Long id;

  private String title;

  private boolean completed;

  @Temporal(TemporalType.TIMESTAMP)
  private Date creationDateTime;
  
  public ToDoTask()
  {
  }

  public Long getId()
  {
      return id;
  }

  public void setId(Long id)
  {
      this.id = id;
  }

  public String getTitle()
  {
      return title;
  }

  public void setTitle(String title)
  {
      this.title = title;
  }

  public boolean isCompleted()
  {
      return completed;
  }

  public void setCompleted(boolean completed)
  {
      this.completed = completed;
  }

  public Date getCreationDateTime()
  {
      return creationDateTime;
  }

  public void setCreationDateTime(Date creationDateTime)
  {
      this.creationDateTime = creationDateTime;
  }
}

As you can see, the Wildfly archetype has done the work for us to connect Hibernate with Wildfly’s built-in database, H2. We simply annotate our entity as above and the corresponding table will be created as soon as we deploy this application.

Next, we want to create a class that will perform the CRUD operations on this entity. For operations that make real changes to our persistence, i.e. the write operations, the CUD part of our CRUD, we need the transactionality, but we don’t want to write it ourselves. Therefore we opt for a stateless session bean as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

package com.pietergrobler.todo.service;

import javax.ejb.Stateless;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import com.pietergrobler.todo.model.ToDoTask;

@Stateless
public class ToDoTaskManagement
{

  @Inject
  private EntityManager em;

  @Inject
  private Event<ToDoTask> taskChangeEvent;

  public ToDoTask saveToDoTask(ToDoTask task)
  {
      if(task.getId() != null)
          em.merge(task);
      else
          em.persist(task);
      taskChangeEvent.fire(task);
      return task;
  }

  public ToDoTask removeTask(Long id)
  {
      ToDoTask task = em.find(ToDoTask.class, id);
      if(task != null)
      {
          em.remove(task);
          taskChangeEvent.fire(task);
          return task;
      } else
          return null;
  }

}

The first method will handle creating and updating, the second removal.

For the read operation, we create a separate, lighter class that will not employ all the transactionality. However, we still want to be able to inject it effortlessly into other classes, so we decide on a @ApplicationScoped CDI bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

package com.pietergrobler.todo.data;

import java.util.List;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import com.pietergrobler.todo.model.ToDoTask;

@ApplicationScoped
public class ToDoListRepository
{

  @Inject
  private EntityManager em;

  public List<ToDoTask> getAll()
  {
      CriteriaBuilder builder = em.getCriteriaBuilder();
      CriteriaQuery<ToDoTask> criteria = builder.createQuery(ToDoTask.class);
      Root<ToDoTask> root = criteria.from(ToDoTask.class);
      criteria.select(root).orderBy(
              builder.desc(root.get("creationDateTime")));
      return em.createQuery(criteria).getResultList();
  }

}

Here you’ll notice a bit of cheeky Criteria API bits. We can query our persistence layer within the safety of strongly typed queries. Nice.

Cleverly, as entities are updated in the ToDoTaskManagement class, it fires an event. The following class listens to these events and updates itself by calling an injected reference of ToDoListRepository to update a cached list of all todo tasks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

package com.pietergrobler.todo.data;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;

import com.pietergrobler.todo.model.ToDoTask;

@RequestScoped
public class ToDoListProducer
{

  @Inject
  private ToDoListRepository repository;

  private List<ToDoTask> tasks;

  @Produces
  public List<ToDoTask> getAllTasks()
  {
      return tasks;
  }

  @PostConstruct
  public void refreshList()
  {
      tasks = repository.getAll();
  }

  public void onToDoListChange(
          @Observes(notifyObserver = Reception.IF_EXISTS) final ToDoTask task)
  {
      refreshList();
  }

}

Even better, it @Produces this cached list, which means this constantly self-updating list can be injected anywhere else, as you’ll soon see, or already know.

Finally, we arrive at the point where we implement the REST service. This class only references our ToDoTaskManagement class and the produced list from the ToDoListProducer class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

package com.pietergrobler.todo.rest;

import java.util.List;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.pietergrobler.todo.model.ToDoTask;
import com.pietergrobler.todo.service.ToDoTaskManagement;

@Path("/tasks")
@RequestScoped
public class ToDoListRESTService
{

  @Inject
  private List<ToDoTask> toDoList;

  @Inject
  private ToDoTaskManagement manager;

  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public List<ToDoTask> allTasks()
  {
      return toDoList;
  }

  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  public ToDoTask addTask(ToDoTask task)
  {
      return manager.saveToDoTask(task);
  }

  @PUT
  @Path("{id}")
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  public ToDoTask editTask(ToDoTask task)
  {
      return manager.saveToDoTask(task);
  }

  @DELETE
  @Path("{id}")
  @Produces(MediaType.APPLICATION_JSON)
  public ToDoTask removeTask(@PathParam("id") Long id)
  {
      return manager.removeTask(id);
  }

}

You’ll notice we include the standard operations needed for our corresponding Backbone.js model:

@GET for getting the full list (already ordered in descending chronological order by virtue of the query we used earlier)
@POST for creating a new task
@PUT for updating an existing task
@DELETE for copying a task - just joking - are you still awake?

Also note that we use @Produces in this class, but it is not related to the previous one. This one is from Java’s REST library, javax.ws.rs.*.

We deploy the application as described in Part 1 of this series and we are curious whether everything is behaving as we expect.

Of course, this is where SoapUI is a godsend. Create a new project, then a test suite, then a test case, and finally a test step, an HTTP Test Request, to be precise. The endpoint will likely be

http://localhost:8080/todo-web/rest/tasks

Let’s add a task. Here’s how:

POST SoapUI

You can simply open the browser and point it to http://localhost:8080/todo-web/rest/tasks to follow along with the changes you cause.

After this step, you’ll see similar to

[{"id":1,"title":"Test","completed":false,"creationDateTime":1421449723486}]

For good measure, let’s update this one’s title and completed value, like this:

PUT SoapUI

Notice the task’s id is appended to the URL: /1. Refreshing the browser will give you:

[{"id":1,"title":"Updated title","completed":false,"creationDateTime":1421449723486}]

And finally we decide this task has been with us long enough, and we get rid of it:

DELETE SoapUI

Notice we pass in no json this time, but again have appended the id to the URL:

http://localhost:8080/todo-web/rest/tasks/1

For our next step we might well decide to run the front-end from a different port - on a different server, even! Therefore, we need to add something that will decorate our responses with the appropriate headers to allow this sort of thing. Let’s create a filter that we just drop into the ../rest.* package.

Before we can use the javax.servlet.* library, we need to add this as a dependency in todo-web’s pom.xml, because the Maven archetype did not include this for us:

1
2
3
4
5
6
7

<dependency>
  <groupId>org.jboss.spec.javax.servlet</groupId>
  <artifactId>jboss-servlet-api_3.1_spec</artifactId>
  <scope>provided</scope>
</dependency>
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

package com.pietergrobler.todo.rest;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

@WebFilter("/rest/*")
public class HeaderDecorationFilter implements Filter {

  public void destroy() {
  }

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      ((HttpServletResponse)response).addHeader("Access-Control-Allow-Origin", "*");
      ((HttpServletResponse)response).addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
      ((HttpServletResponse)response).addHeader("Access-Control-Allow-Methods", "GET, OPTIONS, POST, PUT, DELETE");
      chain.doFilter(request, response);
  }

  public void init(FilterConfig fConfig) throws ServletException {
  }

}

That’s it. The back-end is now more than able to cope with the most confrontational of requests from our front-end. In the next post, we’ll set up camp for the front-end work.

Comments