Sunday, June 10, 2007

Working with JMaki

I recently had an opportunity to use some of the JMaki UI components and it took me some googling to figure out how to pass data dynamically (which is what most of the time you will want and unfortunately all examples use some static data in the JSON format) to the UI components. JMaki's integration with Netbeans makes it really simple to have those nice Web UI components working for you in a jiffy (like grid, tree, menu, captcha, autocomplete etc). Though i am a big fan of DWR (having used the reverse ajax in DWR 2.0 for an event browser application to show events in real-time) for Ajax support in my work, i did like the Ajax-enabled UI Components that come with JMaki. Another nice thing about JMaki is, it provides a common data model for multiple implementations of a certain UI component. For example, you have a Yahoo UI Tree and a dojo toolkit tree component. Since JMaki provides the abstraction by keeping the data models same for both these tree components, so we have the option to switch between these implementations with almost no change to code.

Now going back to the point (the reason i am writing this post after all) ... the JMaki components accept data dynamically in JSON format and though one can create the JSON format string to pass as value attributes to the widgets, it becomes cumbersome for widgets like trees or grid to escape the quotes and construct the strings. To make our lives easy in constructing the JSON formatted dynamic data, JMaki comes bundled with org.json.* classes (JSONObject, JSONArray etc) using which one can create the data to pass in an elegant and maintainable way. You will need to convert the JSONObject or JSONArray types to their Object literal form using the following code which Greg Murray (JMaki project manager) released in reply to one post on JMaki users forum:


/**
* Converts a JSON Object to an Object Literal
*
*
* @param jo
* @param buff
*
* @return
*
* @throws JSONException
*/
public static String jsonToObjectLiteral(JSONObject jo, StringBuffer buff)
throws JSONException
{
if (buff == null) {
buff = new StringBuffer("{");
} else {
buff.append("{");
}

JSONArray names = jo.names();

for (int l = 0; (names != null) && (l < names.length()); l++) {
String key = names.getString(l);
String value = null;

if (jo.optJSONObject(key) != null) {
value = key + ":";
buff.append(value);
jsonToObjectLiteral(jo.optJSONObject(key), buff);
} else if (jo.optJSONArray(key) != null) {
value = key + ":";
buff.append(value);
jsonArrayToString(jo.optJSONArray(key), buff);
} else if (jo.optLong(key, -1) != -1) {
value = key + ":" + jo.get(key) + "";
buff.append(value);
} else if (jo.optDouble(key, -1) != -1) {
value = key + ":" + jo.get(key) + "";
buff.append(value);
} else if (jo.opt(key) != null) {
Object obj = jo.opt(key);

if (obj instanceof Boolean) {
value = key + ":" + jo.getBoolean(key) + "";
} else {
value = key + ":" + "'" + jo.get(key) + "'";
}

buff.append(value);
}

if (l < names.length() - 1) {
buff.append(",");
}
}

buff.append("}");

return buff.toString();
}

/**
* Converts a json array to string.
*
*
* @param ja
* @param buff
*
* @return
*
* @throws JSONException
*/
public static String jsonArrayToString(JSONArray ja, StringBuffer buff)
throws JSONException
{
if (buff == null) {
buff = new StringBuffer("[");
} else {
buff.append("[");
}

for (int key = 0; (ja != null) && (key < ja.length()); key++) {
String value = null;

if (ja.optJSONObject(key) != null) {
jsonToObjectLiteral(ja.optJSONObject(key), buff);
} else if (ja.optJSONArray(key) != null) {
jsonArrayToString(ja.optJSONArray(key), buff);
} else if (ja.optLong(key, -1) != -1) {
value = ja.get(key) + "";
buff.append(value);
} else if (ja.optDouble(key, -1) != -1) {
value = ja.get(key) + "";
buff.append(value);
} else if (ja.optBoolean(key)) {
value = ja.getBoolean(key) + "";
buff.append(value);
} else if (ja.opt(key) != null) {
Object obj = ja.opt(key);

if (obj instanceof Boolean) {
value = ja.getBoolean(key) + "";
} else {
value = "'" + ja.get(key) + "'";
}

buff.append(value);
}

if (key < ja.length() - 1) {
buff.append(",");
}
}

buff.append("]");

return buff.toString();
}


So, after you have your dynamic data put in JSONObject or JSONArray, you can invoke the corresponding conversion method stated above to get the String form of your JSON data ready to be passed to the component.

For instance, in your tree builder code, you will need to do the following (the example is from this post where the solution was posted by Greg Murray):


public static JSONObject buildTreeData(AuthorizedTeams ateams)
throws JSONException {

JSONObject retValue = new JSONObject();
JSONObject root = new JSONObject();
root.put ("title", "Organizations");
root.put ("expanded", true);
JSONArray data = new JSONArray();

Team[] teams = ateams.getTeams();

for (int i=0; i<teams.length; i++) {
JSONObject teamObj = new JSONObject();
teamObj.put("title", teams[i].getTeamName());
teamObj.put("expanded", true);

JSONArray children = new JSONArray();

User[] teamUsers = teams[i].getMembers();
for (int j=0; j<teamUsers.length; j++) {
JSONObject childObj = new JSONObject();
childObj.put("title",teamUsers [j].getUserName());
children.put(childObj);
}
teamObj.put("children", children);
data.put(teamObj);
}
root.put ("children", data);
retValue.put ("root", root);

return jsonToObjectLiteral(retValue, new StringBuffer());
}

Here is the JSP snippet:

<jsp:useBean id="teams"
class="com.myapp.assignment.AuthorizedTeams"
scope="request"/>
<a:widget name="dojo.tree" value="${teams.teamsData}">

2 comments:

Unknown said...

Hi Rajneesh!!

I was using jmaki static yahoo tree control in my application but as the requirement moved ahead we need to populate jMaki tree from the database, I am really confused and need help to move further. I need to create node names and their respective sub-nodes from the database. I will very thankful to get any help on this.

regards
Amair

Anonymous said...

Hi,
I would also appreciate a sample of binding tree to database.

Thanks

Popular micro services patterns

Here are some popular Microservice design patterns that a programmer should know: Service Registry  pattern provides a  central location  fo...