世界中のユーザーに影響のある Web アプリケーションを作成する際には、2 つの点を考慮する必要があります。1 つは、ページのコンテンツをローカライズして表示する必要があるということ、そしてもう 1 つは、ユーザー入力を検証し、ローカライズされた検証メッセージを表示する必要があるということです。
コンテンツのローカライズを行ったページは、サーバー・サイドでリソース・バンドル (ロケール固有のプロパティー・ファイル) を使用すれば容易に作成することができます。同様に、サーバー・サイドの検証機能を使用して、ローカライズされた検証メッセージを表示することもできます。国際化対応に関しては、既製のフレームワークの多く (Jakarta Struts、Spring、Tapestry、Freemarker など) が意匠を凝らしてサポートしていますが、そうしたフレームワークのほとんどにおいて、クライアント・サイドで行われた検証結果をローカライズされたメッセージで表示する機能が欠けています。
検証がクライアント・サイドで行われる場合には、ローカライズされた検証メッセージを表示することは非常に困難です。メッセージを表示する方法として、ページを作成する際に静的コンテンツや JavaScript による必要な検証メッセージを含めてページ全体を事前に作成しておく方法、あるいはロケール固有のリソース・バンドルを使用してメッセージ・キーを解決する方法があります。ただしそうした方法には暗黙的な制約があります。つまり JavaScript による検証ロジック全体を JSP (JavaServer Page) そのものの中に作成することで、Java™ ベースのメッセージ・キー解決ロジックを再利用できるようにしなければなりません。JavaScript は通常、ページ・デザイナーが作成するものであり、彼らが Java 開発者であるとは限らないことを忘れてはなりません。Java コードと JavaScript を混在させると、Web アプリケーションの開発や保守が複雑になります。
もう少し楽な別の方法として、Ajax とリソース・バンドルを組み合わせる方法があります。この方法を使うと、検証用の JavaScript を JSP 以外のファイルに移動することができます。また、事前作成されたローカライズ・バージョンを使う場合にはすべてのメッセージ・キーが解決されることとなるのに対し、この方法では、必要なメッセージ・キーのみが要求に応じて解決されます。
この記事では、クライアント・サイドで行われる検証の結果を、ローカライズされたメッセージで表示するのが少し簡単になるように、Ajax とリソース・バンドルを組み合わせて使う方法について説明します。ここでは既製のフレームワークを使うことでさらに複雑になるという事態を避け、Ajax の強力さを活用する方法に焦点を当てます。この記事で紹介する方法は、極めて迅速にユーザー入力を検証する必要のある Web 2.0 アプリケーション (ユーザーのアクティビティーを休みなく追跡しているアプリケーションなど) にとって理想的な方法です。
また、JSP ページの中の静的な HTML コンテンツをローカライズする方法については、この記事では説明しません。クライアント・サイドで行われた検証の結果をローカライズされたメッセージで表示するための、Ajax とリソース・バンドルの使い方に焦点を絞ります。ただし、サーバー・サイドでメッセージ・キーを解決するために使われる Java ユーティリティーは、JSP ページの中の静的な HTML コンテンツをローカライズするためにも使用することができます。
国際化 (internationalization) — 技術的な変更をせずに、さまざまな言語や地域に対応できるようにアプリケーションを設計するプロセスを言います。国際化という用語は i18n と省略されることがありますが、これは internationalization の最初の「i」と最後の「n」の間に 18 個の文字があるためです。
ローカライズ (localization) — ロケール固有のコンポーネントや翻訳されたテキストを追加することによってソフトウェアを特定の地域や言語に対応させるプロセスを言います。ローカライズという用語は l10n と省略されることがよくありますが、これは localization の「l」と「n」の間に 10 個の文字があるためです。ローカライズの主な作業はユーザー・インターフェース要素とドキュメントの翻訳です。ローカライズに含まれる作業には、表示される言語や入力される言語の変更だけではなく、関連する他の要素 (数字や日付、通貨などの表示) の変更もあります。音や画像など他のタイプのデータも、文化的に慎重な対応を要する場合にはローカライズが必要となるかもしれません。アプリケーションの国際化が適切であればあるほど、特定の言語や文字エンコーディング方法に対してアプリケーションをローカライズする作業は容易になります。
Ajax — より優れていて高速かつ対話性の高い Web アプリケーションを作成するための手法を言います。Ajax の場合、JavaScript コードは XMLHttpRequest オブジェクトを使ってサーバーと直接通信を行います。このオブジェクトを使うことによって、JavaScript コードはページをリロードせずに Web サーバーとデータを交換することができます。
グローバルな (地理的に分散された) ユーザーを対象とする Web アプリケーションを開発する際には、ユーザーが好む言語や文化に十分配慮し、適切な敬意と注意を払って行う必要があります。Web アプリケーションで国際化をサポートするには、以下の点に対処する必要があります。
- 文化に依存するデータを特定する
- 翻訳可能なテキストをリソース・バンドルに分離する
- 複合メッセージに対応する
- 数字と通貨を適切なフォーマットにする
- 日付と時刻を適切なフォーマットにする
- Unicode 文字プロパティーを使用する
- 文字比較を適切に行う
- Unicode ではないテキストを Unicode に変換する
ローカライズされたメッセージをクライアント・サイドで表示するためのステップ概要
国際化をサポートし、ローカライズされたメッセージをクライアント・サイドで表示する Web アプリケーションを作成する際には、基本的に以下に示す内容が必須事項となります。
- ローカライズされたすべてのページは UTF-8 文字セット (ページ・エンコーディング) をサポートする必要があります。
- クライアント・サイドのすべてのメッセージは、クライアントのロケール固有のリソース・バンドルを使ってサーバー・サイドから取得する必要があります。
- リソース・バンドルはキーと値のペアを保存する必要があります。値には Unicode 文字を使います。
- Ajax を使ってクライアント・サイドの JavaScript からサーバー・サイドのリソースにリクエストを送信します。こうすることによって、キーに対するクライアント・ロケール固有のメッセージを取得するためのリクエストを解決することができます。
- 取得したメッセージを解析し、適切に表示します。
ローカライズされたメッセージをクライアント・サイドで表示するために Ajax を使用する実践的な手法
では必要な作業の詳細に入りましょう。まず基本的な構造を作成し、サンプル・ページを使ってその構造をテストします。そしてその構造を Web アプリケーションの中で繰り返し使用します。
最初に、リソース・バンドルとしてのプロパティー・ファイルを用意します。*.properties ファイルはプロジェクトのクラス・パスに保存され、キーと値のペアを保持し、リソース・バンドルとして使われます (リソース・バンドルは実行時に解決されるロケール固有の検証メッセージを取得するために使われます)。こうした *.properties ファイルはすべて、命名規則に関する Java の国際化標準に従う必要があります。
リスト 1. リソース・バンドルのプロパティー・ファイル
# org/rpd/i18n/bundles/Messages.properties - Resource Bundle for default locale # The sample message key-value pairs... error.loginid.required = User Name is Mandatory. error.useremail.required = Email Id is Mandatory. error.password.required = Password is required. error.password.length = Password Length should not be less than six(6)character. error.confirmpassword.required = Confirm Password is required. error.passwordconfirm.match = Password and Confirm Password does not match. error.firstName.required = First Name is required. error.lastName.required = Last Name is required. |
次に、リソース・バンドルを管理するための Java クラスを作成します。このクラス (ResourceManager.java とします) は、ロケール固有のリソース・バンドルをキャッシュにロードするための関数を公開します。またこのクラスは、指定されたメッセージ・キーとロケールに応じてメッセージの値を取得するためにも使われます。
リスト 2. ResourceManager.java
package org.rpd.i18n.common;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
public class ResourceManager {
// The name and location of the resource bundle.
private final String mMessageBundle = "org/rpd/i18n/bundles/Messages";
// The loaded message cache...
private Map<Locale, ResourceBundle> mResourceCache = null;
// Private instance variable.
private static ResourceManager mManager = null;
// default private constructor.
private ResourceManager(){
mResourceCache = new HashMap<Locale, ResourceBundle>();
}
// Get the locale-specific bundle from cache.
// First load to the cache if not already loaded
public ResourceBundle getBundle(Locale locale){
if(locale == null){
locale = Locale.getDefault();
}
if(mResourceCache.containsKey(locale) == false){
ResourceBundle bundle = ResourceBundle.getBundle(mMessageBundle, locale);
mResourceCache.put(locale, bundle);
}
return mResourceCache.get(locale);
}
// Thread safe Singleton pattern implementation...
private static ResourceManager getInstance(){
synchronized (ResourceManager.class) {
if(mManager == null){
mManager = new ResourceManager();
}
}
return mManager;
}
// Get the message for the key using default locale.
public static String getMessage(String key){
return getMessage(key, null);
}
// Get the message for the key and specified locale.
public static String getMessage(String key, Locale locale){
try{
return getInstance().getBundle(locale).getString(key);
}catch(Exception e){
return "";
}
}
} |
Ajax リクエストを処理するための JSP ファイルを作成します。この JSP ファイル (ここでは MessageResolver.jsp とします) は Ajax リクエストを処理してメッセージ・キー (この JSP へのリクエスト・パラメーターである message-key) を解決します。この JSP ファイルは ResourceManager クラスが公開するメッセージ取得機能を使用して、この JSP へのリクエスト・パラメーターとして渡される各メッセージ・キーを解決します。
リスト 3. MessageResolver.jsp
<%@page import="org.rpd.i18n.common.ResourceManager"%>
<%
// The name of the request parameter representing the input
// "HTML Element - Message Key" combination.
final String REQ_ID = "message-key";
// Message prefix to be used in output string.
final String MSG_PREFIX = "begin::";
// Message suffix to be used in output string.
final String MSG_SUFFIX = "::end";
// The standard "HTML Element - Message Key" delimiter.
final String ELEMENT_KEY_DELIM = ",";
// The "HTML Element - Localize Message" delimiter to be used in
// output string.
final String KEY_VAL_DELIM = "==";
// Find the request parameter containing the "HTML Element - Message Key"
// combination String.
String keysArr = request.getParameter(REQ_ID);
// If the desired request parameter doesn't exist, it means request is invalid.
if(keysArr == null){
out.println("Invalid message key");
} else {
// Split the input using the element - key delimiter (ELEMENT_KEY_DELIM).
String keys[] = keysArr.split(ELEMENT_KEY_DELIM);
// Check if the number of tuples is even. If not, it means the input is incorrect.
if((keys.length%2) != 0){
out.println("Improper elem-key combination: " + keysArr);
} else {
// Iterate through each elem-key combination.
for(int i=0; i < keys.length; i = i + 2){
// Retrieve the localized message against the key. Prepare the result string
// as follows:
// Message Prefix (followed by) HTML Element key (followed by) Key-value
// delimiter
// (followed by) Localized value (followed by) Message suffix.
out.println(MSG_PREFIX + keys[i].trim() + KEY_VAL_DELIM +
ResourceManager.getMessage(keys[i+1].trim(), request.getLocale()) +
MSG_SUFFIX);
}
}
}
%> |
Ajax 呼び出しを扱う JavaScript ユーティリティーを用意します。同時に、一連の JavaScript ルーチンも作成することで (これらを収めたファイルを MessageDisplay.js とします)、MessageResolver.jsp に対する Ajax 呼び出しに渡される入力を適切に作成できるようにします。JSP が想定するリクエスト・パラメーターは、カンマで区切られた一連のストリングです。このストリングは HTML 要素 (プレースホルダー) の識別子とメッセージ・キーのペアで構成され、メッセージ・キーは解決されると、その HTML 要素の中に表示されます。またこの MessageDisplay.js には、解決されたメッセージを、関連する HTML 要素に適切に表示するためのルーチン (displayMessage() メソッド) も含まれています。
リスト 4. MessageDisplay.js
var xmlHttp = null;
var msgKeys = new Array();
var msgPrefix = "begin::";
var msgSuffix = "::end";
var msgDelimiter = "==";
var jspURL = "MessageResolver.jsp";
// reset msgKeys array.
function resetMsgKeys(){
msgKeys = new Array();
}
// Adding to the array of keys
function addMsgKey(elemId, msgKey) {
msgKeys[msgKeys.length] = new Array();
msgKeys[msgKeys.length - 1][0] = elemId;
msgKeys[msgKeys.length - 1][1] = msgKey;
document.getElementById(elemId).innerText = "";
}
//Different browsers use different methods to create XMLHttpRequest objects.
function getXmlHttpObject() {
xmlHttp = null;
try {
// Firefox, Opera 8.0+, Safari
xmlHttp = new XMLHttpRequest();
}
catch (e) { // Internet Explorer
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
alert("Your browser does not support Ajax!");
return false;
}
}
}
return xmlHttp;
}
//To pass on the key to the JSP
function getMessage(key) {
// checking for browser support
xmlHttp = getXmlHttpObject();
if (xmlHttp == null) {
alert("Browser does not support Ajax");
return false;
}
var url = jspURL + "?message-key=" + key;
xmlHttp.onreadystatechange = displayMessage;
xmlHttp.open("GET", url, true);
xmlHttp.send(null);
}
//Response generated against the request
function displayMessage() {
if (xmlHttp.readyState == 4 || xmlHttp.readyState == "complete") {
var localizedMsg = xmlHttp.responseText;
while (true) {
var begInd = localizedMsg.indexOf(msgPrefix);
var endInd = localizedMsg.indexOf(msgSuffix);
if (begInd < 0 || endInd < 0) {
break;
}
var msg = localizedMsg.substring((begInd + msgPrefix.length), endInd);
var elemVal = msg.split(msgDelimiter);
document.getElementById(elemVal[0]).innerText
= document.getElementById(elemVal[0]).innerText + "**" + elemVal[1];
localizedMsg = localizedMsg.substring(endInd + msgSuffix.length);
}
}
} |
テスト用のクライアント JSP/HTML を作成します。このページ (ここでは NewUserRegistration.jsp とします) にはいくつかの入力フィールドがあり、これらのフィールドのデータをクライアント・サイドで JavaScript を使って検証する必要があります。ユーザーが適切なデータを入力しようとして間違えてしまうことはよくあることなので、検証ロジックでは適切なメッセージを表示して即座にユーザーに誤りを知らせる必要があります。検証メッセージはローカライズされている必要があるため、検証ロジックでは先ほど用意した Ajax ユーティリティーを使い、検証で見つかった問題のタイプごとにロケール固有のメッセージを表示する必要があります。
リスト 5. NewUserRegistration.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>New User Registration</title>
<script type="text/javascript" src="ValidateNewUser.js"> </script>
<script type="text/javascript" src="MessageDisplay.js"> </script>
</head>
<body>
<form onsubmit="return validateNewUser();" name="frmRegistration"
id="frmRegistration" action="#" method="post">
<table border="0" width="100%">
<tbody>
<tr>
<td align="right" nowrap="nowrap"> Email ID</td>
<td align="center">:</td>
<td><input type="text" name="emailId" id="emailId" size="20"></td>
<td width="100%"><p id="emailErrMsg"></p></td>
</tr>
<tr>
<td align="right" nowrap="nowrap">User Name</td>
<td align="center">:</td>
<td><input type="text" name="loginId" id="loginId" size="20"></td>
<td width="100%"><p id="loginErrMsg"></p></td>
</tr>
<tr>
<td align="right" nowrap="nowrap">Password</td>
<td align="center">:</td>
<td><input type="password" name="password" id="password"
size="20" ></td>
<td width="100%"><p id="passwordErrMsg"></p></td>
</tr>
<tr>
<td align="right" nowrap="nowrap">Confirm Password</td>
<td align="center">:</td>
<td><input type="password" name="confirmPassword"
id="confirmPassword" size="20"></td>
<td width="100%"><p id="confirmpassErrMsg"></p></td>
</tr>
<tr>
<td align="right" nowrap="nowrap">First Name</td>
<td align="center">:</td>
<td><input type="text" name="firstName" id="firstName" size="20"></td>
<td width="100%"><p id="firstNameErrMsg"></p></td>
</tr>
<tr>
<td align="right" nowrap="nowrap">Last Name</td>
<td align="center">:</td>
<td><input type="text" name="lastName" id="lastName" size="20"></td>
<td width="100%"><p id="lastNameErrMsg"></p></td>
</tr>
<tr>
<td colspan="4" align="center">
<input type="submit" name="cmdSubmit" value="Submit">
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html> |
フォーム・フィールドに検証基準を適用します。このサンプル JSP にはフォームがあり、ユーザーはシステムへの登録手続きを完了するために必要な情報をこのフォームに入力します。このフォームを適切に送信するためには、以下の検証基準を満たす必要があります。
- Email ID フィールドと User Name フィールドは必須です。
- Password フィールドは必須です。パスワードには少なくとも 6 文字が必要です。
- Confirm Password フィールドの値は「Password」フィールドに入力された値と完全に一致しなければなりません。
- First Name フィールドと Last Name フィールドも必須です。
このフォームを検証するための JavaScript ルーチンを作成します。作成した JavaScript ルーチン (ここでは ValidateNewUser.js とします) を HTML フォームの onsubmit イベントで呼び出し、各種のフィールドを検証します。またこのルーチンは、適切なメッセージ・キーとプレースホルダーとしての HTML 要素の ID からなるペアを用意します。これらのペアは、メッセージ・キーを解決してローカライズされたメッセージを表示するために行われる Ajax 呼び出しへの入力として、後ほど必要に応じて使われます。検証テストにパスしたフォームは送信され、ターゲット・アクションが実行されます。
リスト 6. ValidateNewUser.js
function validateNewUser() {
resetMsgKeys();
document.getElementById("loginErrMsg").innerText = "";
document.getElementById("emailErrMsg").innerText = "";
document.getElementById("passwordErrMsg").innerText = "";
document.getElementById("confirmpassErrMsg").innerText = "";
document.getElementById("firstNameErrMsg").innerText = "";
document.getElementById("lastNameErrMsg").innerText = "";
if (document.frmRegistration.loginId.value == "") {
addMsgKey("loginErrMsg", "error.loginid.required");
}
if (document.frmRegistration.emailId.value == "") {
addMsgKey("emailErrMsg", "error.useremail.required");
if (document.frmRegistration.password.value == "") {
addMsgKey("passwordErrMsg", "error.password.required");
} else {
if (document.frmRegistration.password.value.length < "6") {
addMsgKey("passwordErrMsg", "error.password.length");
}
}
if (document.frmRegistration.confirmPassword.value == "") {
addMsgKey("confirmpassErrMsg", "error.confirmPassword.required");
} else {
if (document.frmRegistration.confirmPassword.value !=
document.frmRegistration.password.value) {
addMsgKey("confirmpassErrMsg", "error.passwordconfirm.match");
}
}
if (document.frmRegistration.firstName.value == "") {
addMsgKey("firstNameErrMsg", "error.firstName.required");
}
if (document.frmRegistration.lastName.value == "") {
addMsgKey("lastNameErrMsg", "error.lastName.required");
}
if (msgKeys.length > 0) {
getMessage(msgKeys);
return false;
}
return true;
} |
このアプリケーションを任意の Web サーバー (例えば Tomcat) にデプロイし、サーバー・インスタンスを起動します。次にブラウザー・インスタンス (例えば Internet Explorer) を開き、クライアントの優先言語セットを見つけます。優先言語は図 1 のように英語になっています (ここをクリックすると画像が拡大されます)。
図 1. 言語の優先順位
図 2 のように、ユーザー登録用のページ (NewUserRegistration.jsp) の URL にアクセスします (ここをクリックすると画像が拡大されます)。
図 2. ユーザー登録
User Name フィールド以外のすべてのフィールドに値を入力します。User Name フィールドは空のままにしておきます。Submit をクリックします。User Name の行の近くに図 3 のように検証メッセージが (英語で) 表示されます (ここをクリックすると画像が拡大されます)。
図 3. 値を入力して検証する
ブラウザー (Internet Explorer) に設定されている言語を変更します。English を削除して Hindi を追加します。
図 4. 優先言語を Hindi に変更する
このブラウザー・インスタンスを閉じ、新しいインスタンスを開きます。
同じ (ユーザー登録の) ページに再度アクセスします。「User Name」フィールドを空にしたまま、すべてのフィールドに正しく値を入力します。「User Name」の行の隣に図 5 のように検証メッセージが (ヒンディー語で) 表示されます (ここをクリックすると画像が拡大されます)。
図 5. 更新された検証メッセージ
- メッセージ・キーを解決するためのサーバー・サイドのリソースを用意します。
- リソース・バンドル (Messages*.properties) を用意します。指定されたキーとロケールに対応した、ロケール固有メッセージの値を解決するための Java ユーティリティー (ResourceManager.java) を定義します。
- Ajax 呼び出しに対応する、サーバー・サイドのリクエスト・ハンドラー JSP (ここでは MessageResolver.jsp を使用) を定義します。
- この JSP は、例えばメッセージ・キーなどのリクエスト・パラメーターを想定する必要があります。
- メッセージ・キー・パラメーターの値は、有効なストリングのカンマ区切りリストでなければなりません。
- この値を「,」(カンマ) で区切って分割したときに、エントリーの数は偶数でなければなりません。
- (連続する) エントリーの各ペアを別々に扱う必要があります。最初のエントリーは HTML 要素の ID であり、検証結果のメッセージがこの要素に表示されます。2 番目のエントリーは実際のメッセージ・キーで、これをリソース・バンドルによって解決します。
- 事前に定義された構造に従ってレスポンスを用意します。この構造は、
<メッセージ開始区切り> <HTML 要素 ID> <メッセージ・キー区切り> <キーに対し解決された国際化対応メッセージ> <メッセージ終了区切り>です。 - HTML 要素とメッセージ・キーの各ペアに対して同じフォーマットを繰り返します。
- クライアント・サイドで検証が行われている間は、以下のことを行います。
- プレースホルダーとしての HTML 要素の ID とメッセージ・キーのペアのリストを用意します。すべての HTML フォーム・フィールドを検証し、そうした要素の ID とメッセージ・キーのペアを用意します。
- 上記のペア (要素 ID とメッセージ・キー) のリストを基にカンマ区切りのストリングを作成します。
- サーバー・サイドのリソース (ステップ 1.a で作成した JSP) に対して Ajax 呼び出しを行います。その際、「message-key=<ステップ 2.2 で作成したカンマ区切りのストリング・リスト>」に対するクエリー・ストリングを追加します。
- クライアント・サイドでは、Ajax 呼び出しによるレスポンスを処理する際に以下のことを行います。
- JSPが生成したレスポンス (ステップ 1.f から 1.g で説明したもの) を解析します。
- HTML 要素の ID と、対応するメッセージの値をペアにしたリストを分割します。
- 適切な JavaScript 呼び出しを行い、各 HTML 要素に対して適切にメッセージを表示します。
Ajax を使うと、クライアント・サイドで検証した結果をローカライズされたメッセージで表示することがいかに簡単か、この記事で明らかになったはずです。ここではセットアップを単純に、何も変更しないようにしましたが、この方法は何らかの既製のシステムや手法を使って改善することができます。例えば皆さんの Web アプリケーションが Jakarta Struts などのフレームワークを利用していたとします。そのフレームワークが、リソース・バンドルを活用するためのより高度な方法を、そのままで使える状態で提供している場合には、ResourceManager.java ユーティリティー・クラスを自作する代わりに、それを使えば良いのです。同様に、Web アプリケーションで指定されている標準に従って JavaScript (および Ajax) ルーチンをより洗練された形で作成することも可能です。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| Sample application for this article | LocalizationExample.zip | 14KB | HTTP |
- XML を使った国際化対応に関する手法が「XML の国際化を紹介する」(developerWorks、2007年1月) の中で説明されています。
- 「Unicode and software internationalization」(developerWorks、2000年4月) を読み、Unicode の手法を学んでください。
- この Ajax チュートリアルは Ajax 技術の基本を理解するために役立ちます。
- JavaScript が Web コンテンツの国際化をどのようにサポートしているかを学んでください。
- Struts を国際化するための非常に優れたチュートリアルがあります。
- この資料を読むと Dojo と国際化に関する基本を理解することができます。
- リソース・バンドルによる Java の国際化とローカライズに関する資料を読んでください。

Ritesh Prasad はインドのバンガロールにある Rational Application Developer 開発チームのメンバーです。彼は Indian Institute of Technology で工業技術および管理の修士号を取得しており、またいくつかの Web アプリケーション開発プロジェクトで Java/J2EE プログラマーとして働いてきました。彼は Chordiant や Eiphany など J2EE ベースの CRM フレームワークを経験してきており、また IBM India で Epiphany を扱った最初の人という名誉にもあずかりました。仕事以外では、音楽や家族との時間を楽しんでいます。