Thursday, November 30, 2006

Cache in with JSON

Data validation is one of the most challenging and ever-changing parts of any enterprise Web application. Quite often validation metadata leaves JavaScript modules littered with server-side code. In this article, you'll learn an elegant way to cache metadata on the client side with the help of server code, which provides JSON-formatted (JavaScript Object Notation) stringified metadata. This approach also enables you to handle multivalue and multigroup attributes in a manner similar to Ajax.

Each application targets some domain problem. And each domain has its own set of rules and regulations that put constraints on data. When an application applies those constraints on data, the constraints become validations. All applications need to validate the data that users enter.

Today, applications generally use combinations of if-else statements to validate data. These statements contain validation data that developers either hard-code or put through server-side code. Generally, developers use server-side code to avoid small data changes that can lead to changes in JavaServer Pages (JSP).

You can use JavaScript Object Notation (JSON) to group and cache metadata and use the JavaScript function to access that metadata to validate the user input.

When you have metadata scattered over JavaScript, you can't control how much data the server evaluates and goes to the client. Instead, all server-side code pieces are evaluated and sent to the server. However, when you cache data using JSON, you have full control over how much metadata you send to the client because server-side code generates JSON-formatted metadata. This helps send only metadata to the client that corresponds to the user who will see or enter the data.

You can also use JSON to cache data that the user inputs. Once the program caches the data, it erases the data fields rather than refreshing the screen, similar to Ajax. This way a user can enter another set of data for the same property.

Let's explore metadata caching using JSON.

JSON in brief

With JSON, or JavaScript Object Notation, you represent your JavaScript object in a specific string format. If you assign a string with such a format to any JavaScript variable, the variable will then refer to an object that is constructed from a string assigned to it.

For example, suppose you have a policy object that has these attributes:

* Plan Name
* Description
* Duration

You can represent this policy object in JSON format using the following string:

{"Plan":"Full Life Cover", "Description":"The best life insurance plan", "Term":"20 years"}

If you assign this string to any JavaScript variable, the variable will accept the data in terms of an object. To access the data, give the path of the attribute you want to access. For this example, assign the above string to a variable called policy:

var policy = {"Plan":"Full Life Cover", "Description":"The best life insurance plan", "Term":"20 years"}

Paste this string in your HTML page's header section and write the following alert:

alert(policy.Plan)

If you see this page in any JavaScript-supported browser, you will see that the alert displays the policy plan.

The example

To demonstrate JSON's capabilities, you will take a person object that has a list of vehicle objects and take an object person that can hold one or more vehicles. Each vehicle has the following properties:

* Brand
* Registration Number
* CC

The browser UI should allow users to add multiple vehicles with best application performance (usually an inherent requirement). Each property has some restriction or validation rule attached to it. You'll assign the following rules:

* Brand Name
o Brand Name can never contain a digit.
o Brand Name can contain a maximum of two words separated by a space.
* Registration Number
o Registration Number must be all digits.
* CC
o CC must be all digits.
o CC can be a minimum of 50 and maximum 5000.

You will have three input fields corresponding to the vehicle properties, where a user will enter the information. Next, you'll see how to group the validation messages in a JSON group and how to access them.

Conventional approach

Now, when a user enters 40 CC for the vehicle data, the program must display a message saying that the entry does not fall within the valid CC range. You can show the message simply as in Listing 1:

Listing 1. Conventional code

if(cc < <%= minCC %> || cc > <%= maxCC %>) {
alert(<%= ResourceList.vehicleCCRangeMsg >);
}


ResourceList is a server-side class that holds the internationalized messages in variables like vehicleCCRangeMsg. This approach solves the problems with little mess:

1. This way you add server-side code to all client-side validation functions in order to check conditions and to show messages.
2. If you change the way you organize metadata and messages (such as the server-side classes or variables), you end up changing client script validation functions that use them.

How JSON can help

How would you feel if you have to refer only to a JavaScript variable inside condition statements and alerts rather than server-side code? You won't have server-side code in your JavaScript and the change in server-side metadata and message holding will not affect the client-side script. This would be great, right? Well, that is exactly what you will do when you employ JSON-based metadata caching.

You will use a JavaScript object to group our validation data and messages in a hierarchy. And you will access these messages just like you access the hierarchical JavaScript object. That's it and you are done!

Once you have this JSON metadata object in place, your previous piece of JavaScript will look like Listing 2.

Listing 2. Alert with JSON metadata caching object

if(cc <> vehicleValidationsMetadata.CC.maxCC) {
alert(vehicleValidationsMetadata.CC.RangeMessage);
}


The question now is who or what will prepare the JSON metadata object? Well, only the server can do that. The server must produce this JSON object and provide it to the client (browser). Some Java APIs help you prepare such (in fact, any kind of) JSON objects. See Resources to find those APIs.

A typical approach to generate a JSON metadata object is

1. You prepare a hierarchical Java object for your entities and their validation messages
2. Call toString() on them. These would mostly give you a JSON-formatted string.
3. Store that string away in a request scope.
4. In JSP, get that string and assign it inside the curly brackets of a JavaScript variable value.

The final vehicle metadata object might look like Listing 3.

Listing 3. Validation metadata JSON object

var vehicleValidationsMetadata = {
"BrandName":{
"CanContainDigits":false,
"MaxWords":2,
"FormatMessage":"Brand Name cannot contain digits."
"WordLimitMessage":"Brand Name cannot contain more than two words"
},
"RegistrationNumber":{
"CanContainAlphabets"false,
"CanContainDigits":true,
"FormatMessage":"Registration Number can contain only digits."
},
"CC"
"minCC":50,
"maxCC"5000,
"FormatMessage": "can only be numeric",
"RangeMessage": "CC can be within range of 50 and 5000"
}
}


The server must produce the entire string, except for the first and last lines, because the current user locale might require these messages (and only server-side code can accomplish this). One thing to note here is that this metadata object is only for validating the vehicle. The better encapsulation is if the vehicle metadata object is part of the person metadata object. In that case, rather than create another JavaScript variable, you can just include that metadata object into your person metadata object.

Once you have this metadata object ready, you can use the metadata and messages in that object to validate data input and display messages. Now your JavaScript function that validates vehicle inputs might look like Listing 4.

Listing 4. Vehicle data validation function

function validateVehicleData() {
var brandName = //get brand name from form field
var registrationNumber = //get Registration Number from form field.
var CC = //get CC from form field
var brandNameTokens = brandName.split(' ');
if(brandNameTokens.length > vehicleValidationsMetadata.BrandName.MaxWords) {
alert(vehicleValidationMessages.BrandName.WordLimitMessage);
}
.
.
.
if((!vehicleValidationsMetadata.RegistrationNumber.CanContainAlphabets) &&
isNaN(parseInt(registrationNumber))) {
alert(vehicleValidationMessages.RegistrationNumber.FormatMessage);
}
var ccNum = parseInt(CC);
if(ccNum <> vehicleValidationMessages.CC.maxCC) {
alert(vehicleValidationMessages.CC.RangeMessage);
}
}


Doesn't this code look better? It doesn't have server code littered in JavaScript. It does not need to re-write client scripts if the server side changes the way it stores metadata. It makes the life of a JSP programmer much easier.

Extending client-side data caching

Some Web applications require users to enter multiple data for the same property or object. As an example, the person-vehicle requires a person to enter data for each vehicle she owns. If she owns more than one vehicle, the application must allow her to enter data of more than one vehicle. I will refer to this kind of object as a multigroup attribute. If the multigroup attribute contains any property that can hold multiple data instances, I will call that multivalue attribute.

Now, the problem with multigroup and multivalue attributes is that you have to enter the data in the same input fields. That means before you enter data for the second vehicle, you have to first save the data you entered for the first vehicle. You can solve this problem two ways:

1. Send the first vehicle's data to the server and blank out the input fields to allow the user to enter the next vehicle's data.
2. Cache the data on the client and blank out the input fields to allow the user to enter the next vehicle's data.

The problem with the first approach is that it needs a server visit for each vehicle data entered. This isn't pretty; users will become frustrated when they have to wait for a server response after they enter vehicle data. Alternatively, the second approach has almost zero response time. The user can enter all vehicle data quickly without waiting. But the matter of concern here is how you cache the data on the client side. Here are more ways to store the data on the client:

1. Cache the data in some format into hidden form field(s) as the user clicks to add the next vehicle's data.
2. Cache data into a JavaScript object.

When you store data into hidden fields, you end up manipulating many hidden fields or manipulating hidden field data every time the user enters new vehicle data. This is like you frequently manipulating a string with string operations.

But the second form of caching data offers an object-oriented approach to caching. When the user enters new vehicle data, you create a new element in the array object. There are no clumsy string operations. When the user is done with all the vehicles, you can simply form a JSON string out of that object and send it to the server by storing it in some hidden field. This approach is much more elegant than the first one.

JSON, data caching and Ajax abilities

When you cache data on the client side using JSON, you update the data caching object every time the user clicks on the Add Vehicle button. The JavaScript function to accomplish this task might look like Listing 5.

Listing 5. Function to add vehicle data into JavaScript object for client-side caching

function addVehicleData() {
var brand = //get vehicle brand;
var regNo = //get registration number;
var cc = //get cc;

vehicleData[vehicleData.length] = new Object();
vehicleData[vehicleData.length].brandName = new Object();
vehicleData[vehicleData.length].brandName = brand;
//same way update other two properties
}


Here vehicleData is the JavaScript variable that initializes when a user loads the page. It is initialized to a new array object, which is empty or has vehicle elements from when a user entered vehicles earlier.

Once this function saves the data into a JavaScript object, the program can invoke another function that will clear out the input fields to allow a user to enter new data.

In such applications, you will require the user to enter certain minimum or maximum number of occurrences of multigroup or multivalue attributes. You can put these limits into a JSON metadata object. In this case, your earlier metadata object will look like Listing 6.

Listing 6. JSON metadata object with occurrence limits

var vehicleValidationsMetadata = {
"MIN_OCC":0,
"MAX_OCC":10,
"MAX_OCC_MSG":" Your message....",
"MIN_OCC_MSG":" Your message.....",
//Everything else is the same
}


Then your addVehicleData() function will validate the data on occurrences first and will add data to the JavaScript object only if the total occurrences are within the allowed limits. Listing 7 shows how you check this.

Listing 7. JSON metadata object limit check


function addVehicleData() {
if(vehicleData.length == vehicleValidationsMetadata.MAX_OCC-1) {
alert(vehicleValidationsMetadata.MAX_OCC_MSG);
}
//Everything else is the same
}


The function that is called when a user submits a page actually validates for minimum occurrences. The biggest advantage of this approach is that the screen doesn't refresh to enter new vehicle data. Providing such static screens was the primary objective of Ajax technology and you can accomplish this with JSON as well. This is all about updating the JSON data object and manipulating the HTML DOM tree through JavaScript. The user response time is minimal as everything executes on the client side only. You can use JSON to provide Ajax abilities to your application.

When a user clicks the Save button, the program calls another JavaScript function that will stringify this JSON object and store it in the hidden form field that the program submits to the server. JSON.js (see Resources) has a JSON.stringify() function that takes the JavaScript object as input and returns string output.

The server side has to be able to understand a JSON-formatted string and produce a server-side object in order to proceed and save the data. The Web site http://www.json.org/java/index.html offers a Java API that serves most of these needs for Java-based applications.

Conclusion

You saw powerful uses for JSON in this article. To summarize:

1. JSON provides an elegant and object-oriented way to cache metadata on client.
2. JSON helps separate validation data and logic.
3. JSON helps provide an Ajaxian nature to a Web application.

No comments: