Modern Web Architecture: The HTML5 Web Storage

Abstract

One of the most important features of HTML5 is the Web Storage feature. Using the Web Storage feature, the client state can be saved on the browser level without consuming the network bandwidth or the server memory. The Web Storage increases the scalability of the web applications on the server level and on the network level. In this article, I will show you how to work with the HTML5 Web Storage feature.

Difference between the old cookies and the HTML5 Web Storage

Unlike cookies, the HTML5 Web Storage is more scalable. The HTML5 Web Storage content is not transferred between the client and the server per every request. This means using the HTML5 Web Storage, you can store unlimited amount of information on the browser without affecting the network bandwidth. While the web cookies have a limited size, and are transferred between the server and the client per every request.

Checking if the browser is supporting the HTML5 Web Storage

HTML5 Web Storage is supported in most of the modern browsers (IE8, Firefox, Safari, Chrome, and Opera). To check if the Web Storage is supported, check if the web storage objects are defined as follows.

function isStorageSupported() {
	if (typeof(localStorage) === "undefined" || typeof(sessionStorage) === "undefined") {
		alert("Web Storage is no suppored ...");
		return false;
	}
	
	return true;
}

The HTML5 Web Storage Objects

The Web Storage is represented by two main objects the localStorage object and the sessionStorage object. The main difference between them is that the localStorage object is stored in the browser with no expiration date, however, the sessionStorage object is stored in the browser and is removed once the user session ends (i.e., its life time is the user session). It is important to know that there is another difference which is localStorage can work in local mode while the sessionStorage can work only inside a hosted page on the server.

If you try to run the sessionStorage in local mode, you will face an error. For example, the error message in Firefox is:

Operation is not supported

I created an example that illustrates how to use the HTML5 Web Storage objects. In this example, there is a text area “information” field and four buttons for (saving the “information” field value in localStorage, retrieving the stored “information” field value from localStorage, saving the “information” field value in sessionStorage, retrieving the stored “information” field value from sessionStorage).

To store any data in the localStorage object, just add the information in the (key, value) form as follows:

localStorage.key = value;

In the example to store the “information” field data in the localStorage object:

localStorage.information = document.getElementById("information").value;

To retrieve the data from the localStorage object, you can retrieve it using the key as follows:

alert(localStorage.key);

In the example to get the “information” data from the localStorage object:

alert("Data from local storage is: " + localStorage.information);
document.getElementById("information").value = localStorage.information;

Using the sessionStorage object is pretty the same as localStorage. In the example to store the “information” field data in the sessionStorage object:

sessionStorage.information = document.getElementById("information").value;

To get the “information” data from the sessionStorage object:

alert("Data from session storage is: " + sessionStorage.information);
document.getElementById("information").value = sessionStorage.information;

I attach below, the complete example code:

<!DOCTYPE html>
<HTML>
<HEAD>
	<TITLE>Welcome to the WebStorage test</TITLE>
	
	<SCRIPT type="text/javascript">
	
		function isStorageSupported() {
			if (typeof(localStorage) === "undefined" || typeof(sessionStorage) === "undefined") {
				alert("Web Storage is no suppored ...");
				return false;
			}
			
			return true;
		}
	
		function storeInformationInLocalStorage() {
			if (isStorageSupported()) {
				localStorage.information = document.getElementById("information").value;
			}
		}
		
		function readInformationFromLocalStorage() {
			if (isStorageSupported()) {
				alert("Data from local storage is: " + localStorage.information);
				document.getElementById("information").value = localStorage.information;
			}			
		}		
	
		function storeInformationInSessionStorage() {
			if (isStorageSupported()) {
				sessionStorage.information = document.getElementById("information").value;
			}
		}
		
		function readInformationFromSessionStorage() {
			if (isStorageSupported()) {
				alert("Data from session storage is: " + sessionStorage.information);
				document.getElementById("information").value = sessionStorage.information;
			}				
		}	
	
	</SCRIPT>
</HEAD>
<BODY>
	<label for="information">Enter some information in the textArea: </label><br/>
	<textarea id="information" rows="2" cols="20"></textarea>	
	<br/><br/>

	<INPUT TYPE="button" value="Store in the localStorage" onclick="javascript:storeInformationInLocalStorage()"/>
	<INPUT TYPE="button" value="Read from the localStorage" onclick="javascript:readInformationFromLocalStorage()"/>

	<br/>

	<INPUT TYPE="button" value="Store in the sessionStorage" onclick="javascript:storeInformationInSessionStorage()"/>
	<INPUT TYPE="button" value="Read from the sessionStorage" onclick="javascript:readInformationFromSessionStorage()"/>	
</BODY>
</HTML>

You can delete any of the key/value pairs in the Web Storage using the sessionStorage.removeItem(key) and the localStorage.removeItem(key). If you want to delete all of the key/value pairs, you can use the sessionStorage.clear() and localStorage.clear().

I attach the example for your reference here.

Using JTA inside OpenJPA in the WebSphere 7 Environment (Without EJBs)

In some situations, you may need to manage the JTA transactions manually without using EJBs. In this post, I will show you how to do this.

Let’s see an example of a (persistence.xml) file that uses a JTA data source:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
	<persistence-unit name="SchoolTestJPA" transaction-type="JTA">
		<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>	
		<jta-data-source>jdbc/school</jta-data-source>			
		<class>jpa.beans.Address</class>
		<class>jpa.beans.Person</class>
		<properties>
			<property name="openjpa.TransactionMode" value="managed"/>
    		        <property name="openjpa.ConnectionFactoryMode" value="managed"/>
		</properties>		
	</persistence-unit>
</persistence>

Thanks to the joinTransaction API of the JPA EntityManager, you can make the EntityManager able to join the current active JTA transaction. Let’s see how you can do this.

EntityManagerFactory emf = PersistentManager.getInstance().getEntityManagerFactory();
EntityManager entityManager = emf.createEntityManager();
UserTransaction userTransaction = null;

try {
        
	Context context = new InitialContext();
	userTransaction = (UserTransaction) context.lookup("java:comp/UserTransaction");
	
	userTransaction.begin();

	entityManager.joinTransaction();
        
	
        // Perform the operations here ...
	entityManager.persist(someThing);
	
	userTransaction.commit();
} catch (Exception exception) {
	exception.printStackTrace();
	
	try {
		if (userTransaction != null && userTransaction.getStatus() == Status.STATUS_ACTIVE) {
			userTransaction.rollback();
		}
	} catch (Exception rollbackException) {
		rollbackException.printStackTrace();
	}
} finally {
	if (entityManager != null) {
		entityManager.close();
	}
}

As you see here, by performing the JNDI lookup on the “java:comp/UserTransaction”, you can get the WebSphere JTA UserTransaction and use it instead of the JPA EntityTransaction.

Running Jasmine on the top of the JsTestDriver test runner

In the previous post, I give you a kickstart about the Jasmine JavaScript unit testing framework. In this post, I will show you how to integrate the Jasmine framework with the JsTestDriver. You will combine the best of them, the power of Jasmine pretty syntax and the power of JSTD test runner.

The JsTestDriver is not only a JavaScript unit testing framework but it is also a test runner that can host other JavaScript unit testing frameworks through adapters. The JsTestDriver can host the following JS unit testing frameworks and more:
1. QUnit.
2. Jasmine.
3. YUI UI Test.

First of all to be able to run Jasmine on the top of the JsTestDriver runner, you need to download the Jasmine JSTD adapter from here: https://github.com/ibolmo/jasmine-jstd-adapter.

In order to run Jasmine test suites on the top of JSTD test runner, you need to load the adapter and the source files before the test files as follows in the jsTestDriver.conf file:

server: http://localhost:9876

load:
  - jasmine/lib/jasmine-1.1.0/jasmine.js
  - jasmine/lib/adapter/JasmineAdapter.js  
  - js-src/Basics.js
  - js-test/BasicsSpec.js 

After that you can start the JSTD server, and then run the test cases as usual. I attached below the screenshot of the Jasmine tests on the top of the JSTD test runner.
jstd jasmine screenshot

I attached here the project source for your reference.

Testing JavaScript code using Jasmine (Kickstart)

Jasmine is one of the JavaScript unit testing frameworks. It has a nice advantage that its syntax is readable and a very human friendly. In this post, I will give you a kickstart to help you start working with Jasmine.

First of all, Let’s create a simple JavaScript object that we need to perform some unit testing on it:

/* Basics.js file */
function Basics() {
}

Basics.prototype.add = function(x, y) {
	return x + y;
};

As shown in the Basics.js file, Basics is a simple JavaScript object that contains one method that adds the x and y parameters and finally returns the result to the caller.

To start working with the Jasmine framework, download the framework from http://pivotal.github.com/jasmine/download.html. Make sure that you have the following folder structure after extracting the downloaded zip file:
jasmine structure

You are having three folders and one html file.
1. lib folder: contains the source files of the Jasmine framework.
2. src folder: contains the source JavaScript files that will be tested.
3. spec folder: contains the testing JavaScript files.
4. SpecRunner.html file: is used for running the JavaScript test suites.

Place the Basics.js in the src folder after making sure that you remove all the old contents of the src and the spec folders.

Now, Let’s write the test suite in the BasicsSpec.js file.

describe("Basics", function() {
  var basics = new Basics();  

  it("should be able to make correct addition", function() {
    expect(basics.add(3, 2)).toEqual(5);
  });

});

As we see here, the testing syntax is very human friendly, it means “describe Basics object which should be able to make correct addition”. The describe keyword represents a test suite that can contain one or more specs. Every spec is represented by the it keyword.

Inside the spec, there is an expectation that expects the basics.add(3, 2) is equal to 5. In Jasmine, the expectation is represented by the expect keyword and the equality checking is represented by a matcher called toEquals.

In Jasmine, there are many other built-in matchers; you can find all of them here: https://github.com/pivotal/jasmine/wiki/Matchers.

Finally, do not forget to remove the old source and spec JS includes from the SpecRunner.html and to add the new includes instead:

  <!-- include source files here... -->
  <script type="text/javascript" src="src/Basics.js"></script>  
  
  <!-- include spec files here... -->
  <script type="text/javascript" src="spec/BasicsSpec.js"></script>

After running the SpecRunner.html file, you will find the following screenshot telling you that the test spec runs successfully.

screenshot

I wish this kickstart can be useful for you. For your reference, download the kickstart example from here.

Unable to open kernel device “\\.\vmci” solution

I found this error when trying to run a Redhat Linux VMware image using the VMware player on my Windows XP operating system.

Unable to open kernel device "\\.\vmci": 
The system cannot find the file specified. 
Did you reboot after installing VMware Player?

After some hours of investigation, I fixed the problem by disabling the VMCI (Virtual Machine Communication Interface) on my virtual machine by doing the following:
1. Open the xxxxxx.vmx file using any text editor.
2. Change the following line:

vmci0.present = "TRUE"

to the following:

vmci0.present = "FALSE"

After applying this workaround, the VMware image worked successfully.

Java getting the class path in the runtime

In some cases, you may need to know for debugging purposes from where a specific class is loaded. This happens usually if there are two different versions of the class in the class path (the one used in compilation is different from the one used in the runtime) which results in the popular java.lang.NoClassDefFoundError error).

Thanks to the ProtectionDomain, you can get this information as shown below.

try {
	Class myclass = Class.forName("org.apache.commons.logging.Log"); /*or any other class you wish*/
	System.out.println(myclass.getProtectionDomain().getCodeSource()
			.getLocation());

} catch (ClassNotFoundException e) {
	e.printStackTrace();
}

Detecting the Page Leave event in JavaScript

You may need to detect if the user is leaving your web page for displaying a warning message to the user mentioning that he may not leave the page and the form is containing data filled by him. To be able to detect this event in JavaScript, you need to deal with the "onbeforeunload" event. The following example explains the idea.

In this example, there is a simple form that contains an input text. When the user enters something in the input text, a warning message appears.

<HTML>
<HEAD>
	<TITLE>Welcome to the test Page</TITLE>
	<SCRIPT type="text/javascript">
		window.onbeforeunload = function(event) {
			
			if (hasData()) {
				return "You entered information in the page. Are you sure you want to leave now?"; // Very important
			}
		}
		
		function hasData() {
			var someThing = document.getElementById("someThing");
			
			if (someThing.value != "") {
				return true;
			}		
			
			return false;
		}
	</SCRIPT>
	
</HEAD>
<BODY>
	<H1>Welcome to the test page</H1>
	
	<FORM>
		<LABEL for="someThing">Enter something here:</LABEL>
		<INPUT type="text" id="someThing"/>
	</FORM>
</BODY>
</HTML>

The "onbeforeunload" event is called when the user tries to leave the page. As shown in the code, to display the interruption message "You entered information in the page. Are you sure you want to leave now?", you have to specify the interruption message in the return of the event. The interruption message is displayed as shown in the figure below.
IE Preview

This code works with me on IE, Firefox, and Safari. I wish that this tip can be useful for you.

Generating Keys for Google Maps API Using the APIs Console

I’m writing this post because I was asked many times how to generate keys for the web sites that are still using Google Maps APIs version 2 (or using GMaps4JSF that is still using Google Maps APIs version 2). Many users were confused because Google removed the key generation mechanism from the Google signup page and some of the users thought that it is no longer supported to generate keys for Google Maps version 2 applications. Fortunately, generating new keys for GMaps v2 applications is still supported.

Here are the steps that I follow for generating new key for my Google Maps API version 2:

  • Login to the APIs console at https://code.google.com/apis/console with your Google Account.
  • Activate the Google Maps v2 service by clicking the “Services” link of the left menu and then enabling the service as shown in the figure below:

    Figure1

  • Click on the “API Access” link of the left menu, then click on the “Create new browser key …” button, the following dialog will appear to you:

    Figure2

  • Enter the URL of your web site, and then click on the “Create” button, you will find your GMaps v2 key attached in the API access page as shown in the figure below:

    Figure3

Finally you can use this key for your GMaps v2 script include as follows:

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABCDEFGHIJK&sensor=false"
            type="text/javascript"></script>

This is all about; I wish that this tip can be useful for you.

References:
https://developers.google.com/maps/documentation/javascript/v2/introduction#Obtaining_Key.

“Ajax Status Zero” Resolution

“Ajax status is zero” is one of the hardest errors to debug especially when the Ajax readyState is 4. If we looked at the XMLHTTPRequest documentation, we will find that the readyState attribute can have one of the following values:

  • 0 “The object has been constructed.”
  • 1 “The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method.”
  • 2 “All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available.”
  • 3 “The response entity body is being received.”
  • 4 “The data transfer has been completed.”

This means that although the data transfer is completed, the status is not OK (not 200).

After some hours of investigation, I found that the XHR (XMLHTTPRequest) zero status means that there is a permission problem of the Ajax request. In other words, the Ajax request is trying to access a domain that the request is not authorized to access.

The actual problem was that my JavaScript JsTestDriver asynchronous test case was running on the JsTestDriver server which is using a different port other than the one that is used by the application server which hosts the Ajax servlet.

The other interesting point to mention is that I only faced this issue on Firefox 10 while in Internet Explorer 8, the Ajax request worked without any problems.

To solve this problem, I authorized the Ajax request that comes from the JsTestDriver server to access the application server by setting the "Access-Control-Allow-Origin" header from my servlet as follows.

response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:42442");

The "http://127.0.0.1:42442" is the JsTestDriver server address from which the Ajax request is constructed and sent to the application server.

After making this workaround the scenario worked fine on all the browsers, I wish that this tip can be helpful for you.