Building the request handling layer

The web request handling layer for Ext JS 4 clients is a JSON-generating proxy to the service layer interfaces. The domain entities are converted into JSON representations within this layer; so our first step is to create some helper code to make this task easier.

There are several excellent open source JSON generation projects that can assist in this task including Jackson (http://jackson.codehaus.org) and Google Gson (http://code.google.com/p/google-gson/). Such libraries parse POJOs into an appropriate JSON representation via their declared fields. With the release of Java EE 7, we no longer have a need for third-party libraries. The Java API for JSON Processing (JSR-353) is available in all Java EE 7-compliant application servers including GlassFish 4. We will leverage this API for generating and parsing JSON data.

Note

If you are unable to use a Java EE 7 application server, you will need to select an alternate JSON-generating strategy, such as Jackson or Google Gson.

Preparing for JSON generation

Our first addition is a new domain interface:

package com.gieman.tttracker.domain;

import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;

public interface JsonItem{

    public JsonObject toJson();
    public void addJson(JsonObjectBuilder builder);

}

This very simple interface defines two methods to help with JSON generation. The toJson method creates a JsonObject that represents the entity. The addJson method adds the entity properties to a JsonObjectBuilder interface. We will see how these two methods are used very soon.

Each of our domain entities will need to implement the JsonItem interface, and this can be achieved by simply adding the interface to the abstract superclass of all the domain entities:

package com.gieman.tttracker.domain;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
public abstract class AbstractEntity implements JsonItem, Serializable{
    
    @Override
    public JsonObject toJson() {

        JsonObjectBuilder builder = Json.createObjectBuilder();
        addJson(builder);
        return builder.build();
    }
    
}

The JsonObjectBuilder interface defines a set of methods that add the name/value pairs to the JSON object associated with the builder. The builder instance adds the fields defined in the descendent classes that implement the addJson method. We will start with the Company object.

Implementing the Company addJson method

The addJson method that needs to be added to the Company class is as follows:

@Override
public void addJson(JsonObjectBuilder builder) {
  builder.add("idCompany", idCompany)
     .add("companyName", companyName);
}

The JsonObject representation of the Company instance is created by calling the builder.build() method in the superclass. The generated JsonObject can then be written by a JsonWriter instance to an output source.

Implementing the Project addJson method

The addJson method that needs to be added to the Project class is as follows:

@Override
public void addJson(JsonObjectBuilder builder) {

  builder.add("idProject", idProject)
     .add("projectName", projectName);

  if(company != null){
     company.addJson(builder);
  }
}   

Note that it is always a good practice to perform null object tests before accessing the object methods. It is possible to create a project object without a company instance and hence we perform the company != null test prior to adding the company JSON properties to the project builder instance. We could have used the following code to add the company properties to the project builder instance directly:

builder.add("idProject", idProject)
     .add("projectName", projectName)
.add("idCompany", company.getIdCompany() )
     .add("companyName", company.getCompanyName() );

However, we would now have replicated the builder.add("idCompany"…) code across two classes (Company.addJson and Project.addJson), thus making the future maintenance prone to errors. Changing the JSON property name from idCompany to companyId, for example, would require the scanning of code to check for possible usage across all classes, not just the Company class. The creation of Company JSON should belong with the Company class as we have implemented.

Implementing the Task addJson method

This Task class will implement the addJson method as follows:

@Override
public void addJson(JsonObjectBuilder builder) {

  builder .add("idTask", idTask)
     .add("taskName", taskName);

  if(project != null){
     project.addJson(builder);

     Company company = project.getCompany();
     company.addJson(builder);
  }        
}

Note once again how we chain the call to addJson for both the project and company classes to add their JSON properties to the task's builder instance.

Implementing the User addJson method

The User.addJson method is defined as follows:

@Override
public void addJson(JsonObjectBuilder builder) {

  builder.add("username", username)
      .add("firstName", firstName)
      .add("lastName", lastName)
      .add("email", email)
      .add("adminRole", adminRole + "")
      .add("fullName", firstName + " " + lastName);
}

The fullName property is for convenience only; we can just as easily create a fullName field that concatenates the firstName and lastName fields in our Ext JS code. However, keeping this code at the source of the JSON generation allows for easier maintenance. Consider the business change request "add a middleName field to the User entity". The fullName inclusion of the new middleName field is then a trivial exercise and would be available to the Ext JS client without any further changes.

Implementing the TaskLog addJson method

The addJson method adds all of the TaskLog fields to the builder instance. The DATE_FORMAT_yyyyMMdd constant is used to format the taskLogDate to an 8-digit representation of the year/month/day and is added to the TaskLog class as follows:

static final SimpleDateFormat DATE_FORMAT_yyyyMMdd = new SimpleDateFormat("yyyyMMdd");

The addJson method will use the SimpleDateFormat instance to format the taskLogDate field:

public void addJson(JsonObjectBuilder builder) {

  builder.add("idTaskLog", idTaskLog)
    .add("taskDescription", taskDescription)
    .add("taskLogDate", taskLogDate == null ? "" : DATE_FORMAT_yyyyMMdd.format(taskLogDate))
    .add("taskMinutes", taskMinutes);

  if (user != null) {
    user.addJson(builder);
  }
  if (task != null) {
    task.addJson(builder);            
  }
}

The taskLogDate field is being formatted in a way that cannot be misunderstood when converting to a JavaScript Date object in Ext JS clients. Without the use of the SimpleDateFormat instance, the builder instance would call the default toString method on the taskLogDate object to retrieve the String representation, resulting in an output similar to the following:

Wed Aug 14 00:00:00 EST 2013

Using the SimpleDateFormat instance configured with a date pattern of yyyyMMdd will ensure that such a date is formatted to 20130814.

Note

Date formatting in enterprise applications can cause many issues if not approached with a standard strategy. This is even more applicable when we are developing applications to be used worldwide, with multiple timezones and different languages. The dates should always be formatted in a way that can be interpreted in the same way regardless of language, timezone, and user preferences.

A note on JSON

We will be using JSON to transmit data between the GlassFish server and the Ext JS client. The transfer is bidirectional; the server will send the JSON data to the Ext JS client, and the Ext JS client will be sending the data in the JSON format back to the server. The server and client will consume and produce the JSON data.

There are no rules for structuring the JSON data as long as it conforms to the specifications (http://tools.ietf.org/html/rfc4627). Ext JS 4 models allow any form of valid JSON structure through the use of associations; our approach keeps the JSON structure to its simplest form. The previously defined addJson methods return simple, flat data structures without nesting or arrays. As an example, a task instance could be serialized into the following JSON object (formatting included for readability):

{
    success: true,
    data: {
        "idTask": 1,
        "taskName": "Write Chapter 7",
        "idProject": 1,
        "projectName": "My Book Project",
        "idCompany": 1,
        "companyName": "PACKT Publishing"
    }
}

The data payload represents the task object that will be consumed by the Ext JS 4 client. We could have defined the JSON representation of the task object as follows:

{
    success: true,
    data: {
        "idTask": 1,
        "taskName": "Write Chapter 7",
        "project": {
            "idProject": 1,
            "projectName": "My Book Project ",
            "company": {
                "idCompany": 1,
                "companyName": "PACKT Publishing"
            }
        }
    }
}

In this structure we see that the task instance belongs to a project, which in turn belongs to a company. Both these JSON representations are legal; they both contain the same task data in valid JSON format. However, which of these two will be easier to parse? Which will be easier to debug? As an enterprise application developer we should always keep the KISS principle in mind. The Keep It Simple, Stupid (KISS)principle states that most systems work best if they are kept simple and unnecessary complexities should be avoided.

Note

Keep your JSON simple! We know that complex structures are possible; this is achieved only through additional complexities when defining the Ext JS 4 models along with the associated data processing when reading or writing JSON data. A simple JSON structure is easier to understand and maintain.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.249.174