A Django site.
July 2, 2008
» GSOC 2008: Week 5

So, it's time for an update. This week got off to a sketchy start, but it's gained momentum. Let me enumerate what I have done thus far with the project. First, I've added AJAX using jquery. I figured I would use jquery mainly because it provided painless AJAX goodness. Prior to even thinking of using jquery, I wrote my own AJAX code using a tutorial that I found while googling. I had to tweak it a bit, but for the most part, it seemed very standard. However, after I wrote the AJAX equivalent code, it didn't feel too elegant. So, first I'm going to show the AJAX code I wrote; then I'll show you the jquery version; finally, I'm going to show you the servlet which handles the AJAX on the server-side.

First, the AJAX I wrote:


function AjaxValidation(url,callback) {
var req = init()
req.onreadystatechange = processRequest

function init() {
if(window.XMLHttpRequest) {
return new XMLHttpRequest()
} else if(window.ActiveXObject) {
return new ActiveXObject("Mircosoft.XMLHTTP")
}
}

function processRequest() {
if(req.readyState == 4) {
if(req.status == 200) {
if(callback) {
chkSyntaxCallBack(req.responseXML)
}
}
}
}
this.doGet = function() {
req.open("GET",url,true)
req.send(null)
}
}
function chkSyntaxCallBack(responseXML) {
var res = responseXML.getElementsByTagName("result")[0].firstChild.nodeValue
document.getElementById("out").innerHTML = res
}

function checkSyntax() {
var target = document.getElementById("groovyModel")
var url = "${pageContext.request.contextPath}/moduleServlet/groovyforms/createGroovyForm?groovyModel="+escape(target.value)
var ajax = new AjaxValidation(url, chkSyntaxCallBack)
ajax.doGet()
}


I warned you that it wasn't too elegant. Understanding this isn't too hard. Here is the call sequence: init() -> doGet() -> processRequest() -> chkSyntaxCallBack(). Not that bad. Now let's see the jquery version.

$(window).ready(function() {
$("#groovyModel").bind("blur",function() {
$.ajax({
type:'POST',
data: { groovyModel:$("#groovyModel").val() },
url: "${pageContext.request.contextPath}/moduleServlet/groovyforms/createGroovyForm",
cache: false,
success: function(data) {
var res = $(data).find("result").text()
$("#out").html(res)

}
})
});
})

Okay, that's much better. A few things are still happening here. When the window is finished loading, I bind my textarea element which has the CSS id of "groovyModel" to the blur event (lost focus). Then you see the AJAX. Now this is very straight forward. We're using the POST method, we're sending whatever value is inside of the textarea at the time the event is fired, we're posting to a servlet, not going to cache, and when we're done, it's printed to the screen. Very straight forward.

Now, like I said, this is all backed on the server-side by a servlet, which is written in Groovy. So here we go:

/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License") you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.module.groovyforms.web

import javax.servlet.ServletException
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.apache.commons.logging.LogFactory
import org.codehaus.groovy.control.CompilationFailedException

class CreateGroovyFormServlet extends HttpServlet {
def classLoader
static final def log = LogFactory.getLog(CreateGroovyFormServlet.class)
private static final long serialVersionUID = 066373513262051L

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
def generateTemplate = request.getParameter("template")
def generateController = request.getParameter("controller")
def finalMarkup = request.getParameter("markup")
def clazz = URLDecoder.decode(request.getParameter("groovyModel"))
def name = request.getParameter("formName")
def version = request.getParameter("version")
def res = this.checkSyntax(clazz)
if (clazz) {
if (checkSyntax(clazz)) {
response.contentType = "text/xml"
response.setHeader "Cache-Conrol", "no-cache"
response.writer.write "\n\t$res\n"
} else {
response.contentType = "text/xml"
response.setHeader "Cache-Control", "no-cache"
response.writer.write "true"
}
} else {
response.contentType = "text/xml"
response.setHeader "Cache-Control", "no-cache"
response.writer.write "\n\tPlease fill in the Form Model\n"
}
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response)
}

@Override
void init() throws ServletException {
if (log.infoEnabled)
log.info("Initializing...")
classLoader = getClassLoader()
}

def getClassLoader() {
def gcl = new GroovyClassLoader(this.getClass().getClassLoader())
gcl
}

/**
* This method is used to relay errors to the user
* @param clazz the class
* @return the exception message or null if it was successful
*/
def checkSyntax(clazz) {
def sb = new StringBuilder()
sb << "import org.openmrs.*\n\n\n"
sb << clazz
def res = null
try {
getClassLoader().parseClass(sb.toString())

} catch (CompilationFailedException e) {
res = "Exception: ${e.message}"
}
res

}

/**
* Check if it is result groovy code.
* @param clazz the class
* @return whether or not it is result groovy code
*/
def isValidGroovy(clazz) {
def sb = new StringBuilder()
sb << "import org.openmrs.*\n\n\n"
sb << clazz
try {
getClassLoader().parseClass(sb.toString())
} catch (CompilationFailedException e) {
return false
}
return true
}
}


This servlet contains a lot of utility methods. One compiles, one initializes/returns the GroovyClassLoader, and of course doGet(), doPost() and init(). doGet() and doPost() both do the same thing, with doPost() simply delegating to doGet(). The code should be reasonably easy to understand. checkSyntax() returns null if it was parsed cleanly, otherwise it returns the exception message, the stack track wouldn't be useful in my case. It returns an XML tag <result> with "true" if it was successful, the exception message if it was not, and a message stating that the field must be filled in if it's empty or just not passed in. I implicitly import org.openmrs.* to allow for easier access to the OpenMRS domain model classes. The parent classloader for the GroovyClassLoader is set the servlet container's classloader. This gives me access to the classpath when loading Groovy classes.

I still have a bit to do, templating needs to be written in, for the most part it's done. Just have a few problems I'm facing, but I'll get through it. Too many people are relying on me succeeding. I feel that this project could help a lot of people, so i feel pressure to succeed. I still need to write in the "Edit" functionality of the "Manage Groovy Forms" page.

I'm definately making progress. More updates to come, that's for sure.

May 31, 2008
» GSoC 2008: Week 1

Okay, week 1 is nearing an end.I accomplished alot of things.

First, I completed the meta-data storage code. I wrote some tests, which revealed some bugs that needed fixing, and they were. I am happy to say, that the metadata storage works!

Writing the test was difficult due to the fact I store the forms in the system using a static List in my container class. I wound up updating to JUnit 4 to get at the @BeforeClass annotation so that the only one set of forms gets loaded into the container class. This helped me greatly. Additionally, the @AfterClass annotation was handy for cleaning up from the tests.

Secondly, Writing the code for interrogating the model was a piece of cake, thanks to groovy. All code for interrogating the model has 50 lines! That includes a model class I wrote to hold the field types and field names. I'll show you, but before I do, I should note that return statements are optional, and the final statement will be returned.


package org.openmrs.module.groovyforms.util

import java.lang.reflect.Field
import org.openmrs.module.groovyforms.metadata.model.GroovyFormsDomainModel

/*
* Utility class containing methods for class interrogation.
*/
class GroovyFormsClassUtil {
/**
* Interrogates the class for all declared fields and
* stores the type and name in a container class
* @param the {@link Class#getCanonicalName() canonical name of the class}
* @see Class#getCanonicalName()
* @return a reference to a container class containing the type
*/
static def getModel(fields) {
def domainModel = new GroovyFormsDomainModel()
def names = domainModel.fieldNames.&add;
def types = domainModel.fieldTypes.&add;
def f = fields.each {Field field ->
names field.name
types field.type.canonicalName
}
domainModel
}

With groovy, it's so easy and concise (as you can see). Let's explain what's going on. First, I pass in the Field array I get from Field.getDeclaredFields(). Now, groovy adds methods onto the standard JDK classes, one of those methods is a method named each() which takes a closure. Now, back to the point, I pass a Field into the closure. That closure is executed for each element (in this case, a Field). Then I add the name, and the type to a List stored in a container class, now that container class is also written in groovy!


package org.openmrs.module.groovyforms.metadata.model

/*
* Ths class holds information about the properties of the model.
*/
class GroovyFormsDomainModel {

/**
* The field names
*/
def fieldNames = []

/**
* The field types
*/
def fieldTypes = []

}

Now, the fields are Lists, not arrays. Anyways, I've gotten off on a tangent here, so let me get back on track.

What I accomplished:


Week 1:

Code to generate the directory structure, serialization of metadata back/forth between XML and POJOs (Plain Old Java Objects), Wrote tests to ensure everything works in that regard. Additionally, I wrote the code to interrogate the domain model which I will generate the forms from.

Next Week

Write up the templates for the view/controller and write code to do the generation of the view/controller. Write some tests to ensure everything generates correctly.

Unrelated to that, my stored-value card from google came today. It feels nice to be $500 richer! This is going to be the best summer, I'm already having fun doing this. It's amazing seeing the whole project evolve into something amazing.

May 19, 2008
» Google Summer of Code Status Report

I haven't really blogged since I last announced that I was accepted into Google Summer of Code. I have a phone meeting with my mentor to bang out a project plan, I more or less have a general idea of how I want things to go, and he does too. Overall, it should be a very successful summer.

I've been enjoying the Community Bonding period. I have made a lot of friends. My fellow summer of coders are amazing. I planned a potential meet-up for google soc'ers from NY, NJ and CT (to be announced formally when it is more concrete).

Now, onto the fun part, telling you all about my project and how I plan on doing it. I'm gonna break this down. There's a lot of things that need to happen. A lot of data needs to be passed between the front and back ends.

Firstly, Direct Web Remoting (DWR) will be used to grab all the information the users enter into the form and forwards it to the backend whose job it is to generate the form, and then relay it back to the user showing them the result, then saving it to the system. DWR will also be used to provide some AJAX magic.

Then, after I have the data, I need to use reflection on the Form Model and based on the data type, using a templating engine, such as Velocity generate HTML form components.

String, etc: text field or text area; Using some Groovy ExpandoMetaClass magic will aid in deciding if we use a text field or text area.

List: drop-select select box

Boolean: radio or checkbox with some Groovy ExpandoMetaClass magic, i'll add a property which will help aid in deciding which one to use.

After the form is generated, a controller will be generated with default checks that the fields are not empty. This will also be done using Velocity for templating.

Once I have everything generated, it will be saved on the file system someplace with an associated XML file containing all metadata(title,version, description,etc) which will be read in by the system when showing which forms are in the system.

May 14, 2008
» Bus Factor in Open Source Software Development

Leslie Hawthorne posted an interested thread to the Google Summer of Code Student's List regarding the Bus Factor and the related Single point of failure.It presents a large problem in FOSS development.

She posed the following questions:

1) Do you see the bus factor as a problem in Open Source in general?
How about for your project?

2) Do you think that the bottlenecks result from having too few people
involved in a project? How do those bottlenecks get resolved if it is
hard to bring on newcomers due to bottlenecks?

3) What parallels can you draw between the concept of the bus factor,
socially speaking, and reliability engineering?

The best example of how it is a problem in open source can be explained by the saga of Hans Reiser, whom everybody knows killed his wife. He is the lead developer on ReiserFS. Now with him in prison, there is a good chance that ReiserFS will now slowly die due to his incarceration.

Imagine for a moment if you will, that Linus Torvalds got hit by a bus or something related to that. What would happen to the Linux Kernel? Well, it would probably not die, but it would be a HUGE hit since he is the one who leads the development. Would it die? Probably not. The Bus Factor for linux is pretty low.

As for my Summer of Code project, the Bus Factor would be high. Since I am the primary developer.

Applying this socially, every organization is ultimately led by the vision of one person, and usually there are safeties in place to prevent the Bus Factor from even becoming an issue. So this really can't be applied socially in my opinion. BUT if Google were eliminated, Summer of Code would cease to exist. So I suppose it could be applied.

The success and potential failure is usually dependent on one person (or a select few in some cases). Again, referencing Hans Reiser, his project will now most likely fail, may not; but the probability is high. This is the same across all industries.

Now, does anybody else have answers regarding this topic?