Wednesday, September 10, 2008

GSoC wrap-up

The program officially ended on August 18th. I'm awaiting the arrival of my t-shirt!!

Now, I didn't quite have time to finish my project prior to that date since my uncle suddenly passed away on August 10th.

The project itself is about 80 percent completed. All that is left is to get the rendering working and finish up the management page to edit the form metadata as it appears in the system.

My time is now limited since school started up again for me, so as much time as I can I'm going to devote to finishing up this project.

I'd like to thank the following:

  • Burke Mamlin for helping me and answering all the questions I had and guiding me when I was lost.


  • Ben Wolfe for putting up with me and helping me when Burke was MIA.


  • OpenMRS and its wonderful worldwide network of developers for making this project into what it has become.


  • Paul Biondich for encouraging me (along with Burke) to apply for summer of code.


  • Last, but certainly not least, Leslie Hawthorn for managing this program and every problem that popped up. She must have super human powers or something.




The list can only be so long, I feel like I'm accepting an academy award here. It was a great experience, and I will definately continue to maintain my project in whatever free time I can find.

Sunday, August 10, 2008

GSoC 2008: We're in the home stretch

Well folks, I can't believe it's almost over. What a journey. I never imagined I'd be able to do this. I have an (almost) working project. I have a few more things that need to be done.

Let's highlight what IS done:
  1. GroovyForm and its related metadata is stored
  2. Model class is interrogated for its properties and those are stored in a container class.
  3. From the data collected in the container class, I generate markup checking for a predefined set of data types.
  4. The view and its related controller is generated -- sneaking in some groovy magic of course!
  5. GroovyForms are successfully saved into the system, along with their respective, model, view and controller.
  6. Forms are persisted when the module is shutdown and reloaded when it is restarted
What's left:
  1. Editing metadata related to the forms currently in the system
  2. Writing the servlet which handles submissions
  3. Create some sample forms
  4. Documentation
I did plan to add a lot of other stuff such as the ability to create custom form widgets, however there were a few problems which caused me to redirect my focus. These will come in after I finish with Summer of Code.

Wednesday, 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.

Saturday, June 21, 2008

GSoC 2008: Groovy Forms getting some AJAX!

No, not the cleaning product! The "Web 2.0" kind of AJAX! Now where will this goodness be placed? The pages for creating the forms and managing the forms.

First off, I used Direct Web Remoting (DWR) to provide a link between my backend java codebase and the front-end javascript! It's quite amazing. You can choose to publish/unpublish the forms with the tick of a checkbox and DWR will magically set the published attribute on the form to the proper state. I then decided to go one step furthur, and provide a mechanism to backup the forms via xstream to XML. Now, with the XML files, two files are maintained, one individual XML file for each form, and one global one, which makes up the model for the entire system. The rationale for having the XML file for each form is that you can just zip up the form folder, and unzip it into another OpenMRS install and you're good to go. Adding the ability to re-generate the XML files via the management interface is especially handle so that if you make a quick change on one system, then want to install it onto another you can.

Now, DWR will be used for creating the forms as well. This will be done mostly to easily relay errors, such as syntax errors in the Controller and the Model of the groovy form. Don't fear, I'm going to go overboard with AJAX! It'll only be used up until the point of where templates are generated. After that point, a Servlet will take over the bulk of the work (I am undecided on the Servlet bit.).

Now what's next? Several things need to happen.

First, creating the form:
  1. We need to validate that form fields are not empty; also the input must be checked for validity.
  2. The model's syntax needs to be compiled and syntax errors need to be relayed to the user.
  3. We need to get the fields of the class and store them.
  4. We need to generate templates like: <%= textArea(...); %> -- They will not be run it through the template engine immediately until the user has confirmed what they want,
  5. After the view has been tweaked -- it is run through the template engine; at this point we will also run the controller through and generate that and present it at the same time the final view is presented.
  6. The user will be presented with the HTML of the view and Groovy controller and given a final opportunity to tweak it before it is saved to the system.
  7. The form is added to the system -- by default the form is not published.
  8. Finally, to publish the form so that it can be used to enter data, they go to the management screen and tick the checkbox.
  9. The form is now ready to be used for data entry.
Pictures are worth a thousand words so here we go: One and Two.

First one contains one form which is published, the rest are not. The second, no forms are published.

The user interface is intuitive and easy to use. It's a great design, of course I'm biased since It was was me who designed it.

Saturday, June 14, 2008

GSoC 2008: Updates and such

Okay, let's see what was accomplished in the past few weeks:
  1. I tweaked the domain class interrogation code a bit. Basically, now there is a 1:1 relationship between a field and the domain model metadata storage container class instance.
  2. I've started the templating work -- most of it right now is just methods which will be called like: <%= textField(...) %> -- that will generate a text field html form widget.
I know I haven't accomplished much, but there's a reason, I swear!

June 11th I went to Rockville, MD to the Hypoparathyroidism Association's 3rd Annual Hypoparathyroidism Conference. I just got home tonight.

Let me stray off a bit to explain what hypoparathyroidism is. Basically, the parathyroid is a gland in your neck, underneath the thyroid. Most people get it via surgical error, where the surgeon cuts out, or damages the parathyroid. When this occurs, the PTH (Parathyroid Hormone) is no longer produced. Now, this is responsible for regulating among other things, Calcium. Without this present, the calcium levels in the blood drop, and patients start to experience Tetnay, where their muscles involuntarily contract. It's not fun. If the levels drop low enough, you can go into convulsions, and ultimately seizures. Death is also a possibility, which is why it's important for patients with hypoparathyroidism to take their meds (Calcium Supplements, sometimes Magnesium, Vitamin D (usually D2 or D3), and a medication which is the active form of Vitamin D called Calcitriol.) Some patients also take other meds as well. These must be continued for the rest of their lives. I got Hypoparathyroidism idiopathically -- which means the origin nor the cause is known.

Back to the point: I was at this conference, and it's such a rare disease that I don't know many people. So I wound up talking with the people there. As a result, not much work was done. Monday, I plan to get the templating working, then probably do some Front end UI work.

Wednesday, June 11, 2008

Well, that's so NOT groovy

So, I was working on my summer of code project, and I have groovy code along side my java code. I needed to add the groovyc ant task. While i assumed that groovy-all-1.5.6.jar, (note the all) contained everything that was needed, guess what folks, it doesn't! I spent the greater part of the evening tracking down this problem, and then i added the ant-1.7.0.jar and ant-launcher.jar jars, after that suddenly everything worked. That begs the question though, why isn't everything included in the groovy jar?

The problem: NoClassDefFoundError on MatchingTask class.


I figured I would put this out there for others in case they too experience what I did.

Saturday, 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 [email protected] 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.

Thursday, May 29, 2008

GSoC 2008: Progress report

I have made a lot of progress on my Google Summer of Code Project.

First, I've completed the code for the generation of the directory structure for the forms. This is done using the form id, which is the name with all illegal characters removed. The only valid characters left are alpha-numeric and periods. Let me tell you, the regular expression to replace all of those characters was hell to write. But, thanks to the help of Jason Davis, I was able to make it much more readable and easier digest. You've gotta see it to get an idea of how bad it was, so here goes:


/**
* Removes all illegal characters, then removes all spaces and makes it all lower-case.
*
* @param str the form name
* @return a viable form id.
*/
public static String formNameToFormId(String str) {
return str.replaceAll("[\\$\\(\\)%`~!@#&;:\\^=\\+\\?<>\"\\*\\\\////\\\\{\\}'\\]\\[\\|\\s+]", "").toLowerCase();

}

That is pretty much hell on earth to read, and it was hell on earth to type. Here's the *MUCH* simpler version:


/**
* Removes all illegal characters, then removes all spaces and makes it all lower-case.
*
* @param str the form name
* @return a viable form id.
*/
public static String formNameToFormId(String str) {
return str.replaceAll("[^a-zA-Z0-9.]", "").toLowerCase();

}

Note, you can clearly see that i'm negating that entire sequence. It does the SAME thing, but is MUCH more readable. That reads: "replace everything that isn't a letter from A to Z *OR* a to z(lower case letters) *OR* from 0 through 9 *OR* a period. Whereas the above just excluded the invalid characters explicitly but was a MONSTER of a regular expression.

Secondly, metadata persistence is written in, I'm using xstream. It's a great tool for XML serialization.

That's it. Oh, by the way, these are the things I earmarked TWO WEEKS FOR! Now, I push domain class model processing up, will work on that tomorrow.

Tuesday, May 27, 2008

Ready...Set...Code: Google Summer of Code has started!

Today was the official start of Google Summer of Code 2008 Hopefully everybody is finding it a pleasant experience. I have yet to start coding as today was a US Holiday (Memorial Day).

The project plan for the summer has been finalized. I decided to set two-week blocks, rather than do a weekly thing. I chose this, as it's extremely flexible and can scale items either back or forward.

The project plan can be found here. A Google Doc which my mentor and I used to plan the project can be found here. Finally, See my general plan written as a previous blog post.

Best of luck to all the summer of code students!

Tuesday, May 20, 2008

Thank you so much Google!!

Today I got the coveted "Google Book" that all Google Summer of Code students have been talking about constantly! I've flipped through it, it's an amazing book! Want to know the name? Everybody knows it already, it's "Beautiful Code" by O'Reilly.

Thank you so much!!!!!

Monday, 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.

Tuesday, May 6, 2008

Posting code made easier (for everybody else reading your blog!)

I've noticed something while reading my daily blogs, a lot of code is just unreadable because most blog systems (blogger looking at you), screw up indentation, unless you wrap it in a pre tag (opening and closing are both required. This makes it readable for your readers! I've left comments on the blogs that didn't know this, and now they do.

This message is primarily for the Google Summer of Code students, but is useful to the programming community as a whole. When you post code, wrap it in a pre tag and be sure to close them when your code example is complete.

Saturday, May 3, 2008

Groovy 1.6-beta-1 released!

So, i read that groovy released 1.6-beta-1. They kept the mixins syntax that was added. I love the new syntax, it's easy to use, and concise as well.

Congrats to the Groovy team! Great Job!

Monday, April 21, 2008

Accepted to google summer of code!

I was accepted to participate in Google Summer of Code. I will be blogging regularly about my progress. The project I will be working is a Groovy Forms Module, which will enable administrators of OpenMRS to quickly create forms along with HTML and controllers. I think it will be a fun experience.

Wednesday, April 9, 2008

The new groovy mixins syntax

Today, I read this post to the groovy dev list and felt the strong urge to play with it. Now to use this, you'll need to compile the groovy code from the trunk in their subversion repository. Read the tutorial about how to build from source. To avoid the dreaded OutOfMemoryException, be sure to increase the amount of heap available to the JVM by doing: ANT_OPTS=-Xmx512m. Now the code.
 
class DeceptiveIntegerExt {
static def minus(int self, int other) {
self + other;
}
}

Integer.mixin DeceptiveIntegerExt

assert 5 - 5 == 10


Let's explain this code: First, I create my mixin class which I named DeceptiveIntegerExt for the sheer reason that the only purpose was to overload the subtraction operator and make it add the numbers. Then I add the mixin class to the Integer class; finally I assert that my mixin works as it should, and indeed it does. Albeit that this is a VERY simple example, but I wanted to play with it.

That's all for now.

Sunday, April 6, 2008

a CICE Bot

After writing a bot using both BGGA and First-Class Methods (FCM), I wanted to do Concise Instance Creation Expressions (CICE) as well. To compile you will need the cice prototype compiler and the jerklib jar. Now here we go:


import jerklib.ConnectionManager;
import jerklib.ProfileImpl;
import jerklib.Session;
import jerklib.events.listeners.IRCEventListener;
import jerklib.events.IRCEvent;
import jerklib.events.JoinCompleteEvent;

/**
* Created: Apr 6, 2008 10:55:08 PM
*
* @author Robert O'Connor
*/
public class CICEBot {
ConnectionManager manager = new ConnectionManager(new ProfileImpl("cicebot", "cicebot", "cicebot2", "cicebot3"));
Session s = manager.requestConnection("irc.freenode.org");

public CICEBot() {
s.addIRCEventListener(IRCEventListener(IRCEvent e) {
if(e.getType() == IRCEvent.Type.CONNECT_COMPLETE) {
e.getSession().join("#jerklib");
} else if(e.getType() == IRCEvent.Type.JOIN_COMPLETE) {
JoinCompleteEvent jce = (JoinCompleteEvent)e;
jce.getChannel().say("Hello from CICE!!!");
}
});
}

public static void main(String[] args) {
new CICEBot();
}
}


The regular java version looks like this:


import jerklib.ConnectionManager;
import jerklib.ProfileImpl;
import jerklib.Session;
import jerklib.events.IRCEvent;
import jerklib.events.JoinCompleteEvent;
import jerklib.events.listeners.IRCEventListener;

/**
* Created: Apr 6, 2008 10:05:09 PM
*
* @author Robert O'Connor
*/
public class JavaBot {
ConnectionManager manager = new ConnectionManager(new ProfileImpl("javabot", "javabot", "javabot2", "javabot3"));
Session s = manager.requestConnection("irc.freenode.org");

public JavaBot() {
s.addIRCEventListener(new IRCEventListener() {
public void receiveEvent(IRCEvent e) {
if (e.getType() == IRCEvent.Type.CONNECT_COMPLETE) {
e.getSession().join("#jerklib");
} else if (e.getType() == IRCEvent.Type.JOIN_COMPLETE) {
JoinCompleteEvent jce = (JoinCompleteEvent) e;
jce.getSession().sayChannel(jce.getChannel(), "Hi from Java!!!");
}

}


});
}

public static void main(String[] args) {
new JavaBot();
}

}

a first class bot (w/ FCM)

After writing a bot using BGGA, I decided to write one using First-Class Methods. Now to compile this, again you will need the FCM prototype compiler and the jerklib jar.

import jerklib.ConnectionManager;
import jerklib.ProfileImpl;
import jerklib.Session;
import jerklib.events.IRCEvent;
import jerklib.events.JoinCompleteEvent;

/**
* Created: Apr 6, 2008 10:23:06 PM
*
* @author Robert O'Connor
*/
public class FCMBot {
ConnectionManager manager = new ConnectionManager(new ProfileImpl("fcmbot","fcmbot","fcmbot2","fcmbot3"));
Session s = manager.requestConnection("irc.freenode.org");

public FCMBot() {
s.addIRCEventListener(#(IRCEvent e) {
if(e.getType() == IRCEvent.Type.CONNECT_COMPLETE) {
e.getSession().join("#jerklib");
} else if(e.getType() == IRCEvent.Type.JOIN_COMPLETE) {
JoinCompleteEvent jce = (JoinCompleteEvent)e;
jce.getChannel().say("Hello from FCM!!!");
}
});
}

public static void main(String[] args) {
new FCMBot();
}
}

It is much like the BGGA bot; in fact i changed nothing and followed the same design:


import jerklib.ConnectionManager;
import jerklib.ProfileImpl;
import jerklib.Session;
import jerklib.events.IRCEvent;
import jerklib.events.JoinCompleteEvent;
import jerklib.events.listeners.IRCEventListener;

/**
* Created: Apr 6, 2008 10:05:09 PM
*
* @author Robert O'Connor
*/
public class JavaBot {
ConnectionManager manager = new ConnectionManager(new ProfileImpl("javabot", "javabot", "javabot2", "javabot3"));
Session s = manager.requestConnection("irc.freenode.org");

public JavaBot() {
s.addIRCEventListener(new IRCEventListener() {
public void receiveEvent(IRCEvent e) {
if (e.getType() == IRCEvent.Type.CONNECT_COMPLETE) {
e.getSession().join("#jerklib");
} else if (e.getType() == IRCEvent.Type.JOIN_COMPLETE) {
JoinCompleteEvent jce = (JoinCompleteEvent) e;
jce.getSession().sayChannel(jce.getChannel(), "Hi from Java!!!");
}

}


});
}

public static void main(String[] args) {
new JavaBot();
}

}

an IRC Bot written using BGGA

I was curious how hard it'd be to write an IRC Bot using BGGA closures; now to compile this you'll need to grab the prototype and the jerklib jar. So here's the code:

import jerklib.ConnectionManager;
import jerklib.ProfileImpl;
import jerklib.Session;
import jerklib.events.IRCEvent;
import jerklib.events.JoinCompleteEvent;

/**
* Created: Apr 6, 2008 9:19:13 PM
*
* @author Robert O'Connor
*/
public class BGGAIRCBot {
ConnectionManager manager = new ConnectionManager(new ProfileImpl("bggabot","bggabot","bggabot2","bggabot3"));
Session s = manager.requestConnection("irc.freenode.org");

public BGGAIRCBot() {
s.addIRCEventListener({IRCEvent e =>
if(e.getType() == IRCEvent.Type.CONNECT_COMPLETE) {
e.getSession().join("#jerklib");
} else if(e.getType() == IRCEvent.Type.JOIN_COMPLETE) {
JoinCompleteEvent jce = (JoinCompleteEvent)e;
jce.getSession().sayChannel(jce.getChannel(),"Hi from BGGA!!!");
}
});



}

public static void main(String[] args) {
new BGGAIRCBot();

}


}


Now, what would it look like without BGGA? It would like something like this:


import jerklib.ConnectionManager;
import jerklib.ProfileImpl;
import jerklib.Session;
import jerklib.events.IRCEvent;
import jerklib.events.JoinCompleteEvent;
import jerklib.events.listeners.IRCEventListener;

/**
* Created: Apr 6, 2008 10:05:09 PM
*
* @author Robert O'Connor
*/
public class JavaBot {
ConnectionManager manager = new ConnectionManager(new ProfileImpl("javabot", "javabot", "javabot2", "javabot3"));
Session s = manager.requestConnection("irc.freenode.org");

public JavaBot() {
s.addIRCEventListener(new IRCEventListener() {
public void receiveEvent(IRCEvent e) {
if (e.getType() == IRCEvent.Type.CONNECT_COMPLETE) {
e.getSession().join("#jerklib");
} else if (e.getType() == IRCEvent.Type.JOIN_COMPLETE) {
JoinCompleteEvent jce = (JoinCompleteEvent) e;
jce.getSession().sayChannel(jce.getChannel(), "Hi from Java!!!");
}

}


});
}

public static void main(String[] args) {
new JavaBot();
}

}

Thursday, April 3, 2008

a groovy way to count number of lines

Groovy is nice to solve small problems (which usually will never pop up; but may!)

Note: The second example using eachLine() on a text file is the same file i used for my Automatic Resource Management (ARM) blocks example.


/*
this
is
a
string
*/
def str = """this
is
a
string
"""
int num = 0;
str.each { if(it == '\n') num++; }
println num // 4
/**
Doug Lea
Josh Bloch
Bob Lee
**/
num = 0;
new File("names.txt").eachLine { num++ }
println num; // 3


So that's it! 1 line of code to actually count the lines! the other 2 are just initialization and output!

Tuesday, April 1, 2008

April Fools: Byte code style!

Today, I stumbled upon this. It's amusing to say the least; at first i took it seriously but then it clicked, that this was possibly an April fools joke. My suspicions were proven to be true when i took a hex editor to String's bytecode, just to see for myself. I'd just like to say, an April Fool's joke done well Christian!

I cannot talk April Fool's without talking about Google. They have the most creative minds behind them, so it's not shocking they have some pretty imaginative April fool's jokes!

Tuesday, March 25, 2008

Summer of code 2008: what will you be doing?

As posted earlier that OpenMRS is participating in Google Summer of Code as a mentoring open source project. Working with OpenMRS will be highly rewarding knowing that you are single-handedly affecting the lives of people in developing nations ravaged by HIV/AIDS. If you are a student (undergaduate/graduate) you are eligible! So go apply for summer of code with OpenMRS! Student applications opened up yesterday and will be accepted up until Monday, March 31st 2008.

Stop by #openmrs on irc.freenode.org for more information -- ask for docpaul or burke.

Monday, March 24, 2008

Update: weird properties bug in the prototype

Okay, I sent an email to the kijaro mailing list and apparently the runtime library only has support for read-write properties. Which does indeed explain the bugs I was experiencing.
The respone:

Hi robby, thanks for testing, i will incoporate test cases based on your examples
in the test suite.
Currently properties is in a weird state between version 3 and unpublished version 4
of the spec. I've done major design changes. I have rewrittent the runtime support,
drop the writeonly properties from the spec, etc.

Currently the runtime library (java.lang.Property and helper classes)
only support read-write property, i think it explain these bugs.

Expanding on Properties

It it worth nothing that in groovy, properties already exist. let's give an example:

class Book {
String title;
}
def gina = new Book();
gina.title = "Groovy In Action";
println gina.title;


Groovy basically generates the getters/setters behind the scenes, but in essence these are for all intensive purposes -- properties. I felt that this needed to be addressed.

Sunday, March 23, 2008

Java gets some Properties.

There is a proposal to add properties to java. Properties will eliminate the need for getters/setters in the usual javabeans pattern style. I'm sure you wanna see some code examples, so as usual, i'll give you the way it's done currently, in this case following the JavaBeans spec of specifying a getter/setter. To run this code you'll need to go and check out the prototype compiler from the subversion repository at java.net. You will need to register. After you have done that type:
svn checkout https://kijaro.dev.java.net/svn/kijaro/branches/properties kijaro --username username --password yourpassword
replace username and yourpassword with the username and password you registered with.

Apache Ant is required to build the compiler.

Now to compile it (instructions are for users running linux;
if running windows i assume you know your OS properly to adjust this).
1) type cd kijaro/langtools/make
2) type ant -Dboot.java.home=$JAVA_HOME
3) now to compile the code you'll do /path/to/kijaro/bin/kijaro-javac /path/to/ClassName.java setting your classpath as needed.
4) To run this, you can either use /path/to/kijaro/bin/kijaro-java /path/to/ClassName or you can use your installed JRE and do: java /path/to/ClassName

That's all you need to know to run this code. Questions? email me.


/**
* Created: Mar 23, 2008 9:13:54 PM
*
* @author Robert O'Connor
*/
public class BeanExample {
private String userName;

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public static void main(String[] args) {
BeanExample example = new BeanExample();
example.setUserName("rob");
System.out.println(example.getUserName());
}
}

The getters/setters are boiler-plate code that just isn't necessary. Most IDEs will generate getters/setters for you with the click of a mouse; but still it makes your code verbose. Now I wrote three examples for properties, since there are three types: read-only,read-write and write-only. Each example showcases just one of those types for reasons of simplicity. First, I'll tackle the example of a read-only property.


/**
* Created: Mar 22, 2008 5:37:41 PM
*
* @author Robert O'Connor
*/
public class ReadOnlyPropertiesExample {
private String userName;
public property String name get { return userName; };

public ReadOnlyPropertiesExample() {
this.userName = "rob";
}

public static void main(String[] args) {
System.out.println(new ReadOnlyPropertiesExample().userName);
}

}

Already, you can see that we've removed a great deal; and it's not that as verbose as the JavaBean example. Now let's see what happens if I try and write to the property? It's a compile-time error; or at least it should be. As of the latest prototype compiler, it didn't complain and happily let me write to the property. Now let's see a properties example that behaves properly as defined by the spec.


/**
* Created: Mar 23, 2008 8:11:41 PM
*
* @author Robert O'Connor
*/
public class ReadWritePropertiesExample {

private String userName;
public property String name
get { return userName; }
set(String name) { userName = name; };

public static void main(String[] args) {
ReadWritePropertiesExample example = new ReadWritePropertiesExample();
example.userName = "rob"; // set the name
System.out.println(example.userName); // output it.
example.userName = "robby"; // set it to something different
System.out.println(example.userName); // output the new value
}
}

Okay, this is a read-write property; note that example.userName is NOT using direct field access. The final example is a write-only example; note that it is a compile-time error to attempt to retrieve the value; however the compiler currently let's you do it; which in my opinion is bad. I coded against the spec, so to circumvent that, I defined a getter (I know properties are supposed to eliminate those, but I needed a way to test that the value was set properly.)


/**
* Created: Mar 23, 2008 8:45:02 PM
*
* @author Robert O'Connor
*/
public class WriteOnlyPropertiesExample {
private String userName;
public property String name set;

/**
* this is used purely to check that the property set the field's value properly.
* @return the username
*/
public String getUserName() {
return userName;
}

public static void main(String[] args) {
WriteOnlyPropertiesExample example = new WriteOnlyPropertiesExample();
example.userName = "rob"; // we can only *SET* it since it's write-only
System.out.println(example.getUserName());
example.userName = "robby";
System.out.println(example.getUserName());
}

}

Okay, now that you've gotten a taste of what's to come (if this makes it passed the JCP that is!) go out and play!

Saturday, March 22, 2008

Futurama fans: Listen up

There's a nifty unix command you can enter to get random futurama quotes:
curl -Is slashdot.org | egrep '^X-(F|B)' | cut -d \- -f 2

Okay, so how does it work? Let's look at what curl -Is slashdot.org returns:

HTTP/1.1 200 OK
Date: Sun, 23 Mar 2008 01:04:28 GMT
Server: Apache/1.3.37 (Unix) mod_perl/1.29
SLASH_LOG_DATA: shtml
X-Powered-By: Slash 2.005000198
X-Leela: I'm a millionaire! Suddenly I have an opinion about the capital gains tax.
Cache-Control: private
Pragma: private
Vary: User-Agent,Accept-Encoding
Connection: close
Content-Type: text/html; charset=iso-8859-1

Pretty neat eh?
Now, what it does is it looks for lines that start with "X-" and contain F or B after the "X-"; thus bringing up Fry or Bender quotes only :).

Wanna make some money while making a difference?

Hey guys,

OpenMRS is an open source medical records system that is used in many third-world developing countries where HIV/AIDS is an epidemic. Now here's where you can make a difference: They are participating in Google Summer of Code. You can make $4500 this summer while making a difference in the lives of people ravaged by the HIV/AIDS epidemic in developing third-world countries. Here's how it works: at the beginning you will get $500; after the mid-term evalations you will get $2000; at the end you will get the final $2000. Check out the projects you could potentially work on! For an overview click here.

Apply here.

Drop by #openmrs on irc.freenode.org for more information. Ask for docpaul, burke or bwolfe

Friday, March 21, 2008

Swing first class w/ FCM.

I got to play with the First-Class methods (FCM) prototype; it's pretty cool. So here we go: Java version then FCM version.

To run the FCM version: compile it using the prototype; then simply type: java FCMGui and you're set. If you need help feel free to e-mail me.


import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

/**
* Created: Mar 19, 2008 5:48:43 PM
*
* @author Robert O'Connor
*/
public class UsualJavaGui {
JFrame frame = new JFrame("Usual Java Example");
JButton button = new JButton("Press me");

public UsualJavaGui() {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Button pressed");
}
});
frame.add(button);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);

}

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {
public void run() {
new UsualJavaGui();
}
});

}
}

Standard java Swing GUI with a frame and a button; press it a message appears in your console. Now, FCM version:


import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import java.awt.event.ActionEvent;

/**
* Created: Mar 21, 2008 6:55:52 PM
*
* @author Robert O'Connor
*/
public class FCMGui {
JFrame frame = new JFrame("FCM Example");
JButton button = new JButton("Press Me");

public FCMGui() {
button.addActionListener(#(ActionEvent evt) {
System.out.println("Button pressed");
});
frame.add(button);
frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(# { new FCMGui();
});

}
}

Same thing: But what the hell is going on? First off, what we declared is called an anonymous inner method; if you remember, it's a First-Class method meaning that it exists in itself. Currently in java, a method must be enclosed in a class, and cannot be referred to on a first-class level.

Automatic Resource Management Blocks (ARM) in action

I've been a busy blogger lately. Here's my experiment with Automatic Resource Management Blocks (ARM). First, I will show you how resource management is done in java; then i'll give you the ARM way to do things. To run the ARM example you need the latest cice/arm prototype. Now, let's see the java way.
But before I do, You'll need the following (copy and paste it into a text file and name it "names.txt" (no double quotes):
 
Josh Bloch
Bob Lee
Doug Lea

By the way, the names here are of the authors of the Concise Instance Creation Expression/Automatic Resource Management Blocks proposal. Okay, now that you have the file needed to run this program. Save names.text to the same directory where your class will reside and I assume you know how to compile/run a java program.
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.FileReader;
import java.io.File;

/**
* Created: Mar 21, 2008 12:46:07 AM
*
* @author Robert O'Connor
*/
public class JavaExample {
BufferedReader r = null;

public JavaExample() {
try {
r = new BufferedReader(new FileReader(new File("names.txt")));
String line;
while ((line = r.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(r!=null)r.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}

public static void main(String[] args) {
new JavaExample();
}
}

It is overly verbose and cumbersome to clean up resource leaks that could occur. if I eliminated the finally block from my above example and an exception occured, the stream would never be closed and would leak. So we have to use a try-catch-finally to clean up. Remember, finally blocks are always executed. Closing the stream throws an exception so we have to catch that too! Enter Automatic Resource Management Blocks (ARM).

 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

/**
* Created: Mar 21, 2008 12:25:43 AM
*
* @author Robert O'Connor
*/
public class ARMExample {
BufferedReader r = null;

public ARMExample() throws IOException {

do (r = new BufferedReader(new FileReader(new File("names.txt")))) {
String line;
while ((line = r.readLine()) != null) {
System.out.println(line);
}
}
}
public static void main(String[] args) throws IOException {
new ARMExample();
}

}

That is NOT a do-while loop, or a loop at all for that matter. It is the automatic resource management block. As you can see it drastically reduced the boiler plate code, try-catch-finally; it doesn't eliminate unchecked exceptions. You still have to catch what's being thrown and recover from it if possible. The point is to manage your resources automatically, eliminating resource leaks.

Thursday, March 20, 2008

Swinging: BGGA style.

So, to continue on with my playing w/ java closures, I now present Swing event handling: BGGA Style. Again, to compile this you will need the BGGA prototype. You can run it using your installed jre.

First, i'll show you the java version:

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

/**
* Created: Mar 19, 2008 5:48:43 PM
*
* @author Robert O'Connor
*/
public class UsualJavaGui {
JFrame frame = new JFrame("Usual Java Example");
JButton button = new JButton("Press me");

public UsualJavaGui() {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Button pressed");
}
});
frame.add(button);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);

}

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {
public void run() {
new UsualJavaGui();
}
});

}
}

I think you get the gist of what it does. Now the BGGA version.

import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import java.awt.event.ActionEvent;

/**
* Created: Mar 19, 2008 7:35:15 PM
*
* @author Robert O'Connor
*/
public class BGGAGui {
JFrame frame = new JFrame("BGGA Frame");
JButton button = new JButton("Press me");

public BGGAGui() {
button.addActionListener({ActionEvent evt => System.out.println("Button pressed");});
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
// thanks to neil gafter!
SwingUtilities.invokeLater({ => new BGGAGui(); });

}
}

What occurs within the the addActionListener() is that when you click the button, that closure is invoked; it does the same thing the java one does (print "Button pressed" to the screen). I'm not sure how to write the invokeLater() method using BGGA to reduce its verbosity. If anybody knows, could you tell me? When the code is executed; the closure is executed and a frame is displayed; yadda yadda.

Wednesday, March 19, 2008

Concise Instance Creation Expressions (CICE)

Another proposal CICE is being put out there for Java 7. To compile the code posted here you will need the latest cice prototype. You can run it using your installed jre. Now, let's get down to the code! First I'm gonna show you the current Java version, then I'll show you the CICE version.

Java Version

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.SwingUtilities;

/**
* Created: Mar 19, 2008 5:48:43 PM
*
* @author Robert O'Connor
*/
public class UsualJavaGui {
JFrame frame = new JFrame("Usual Java Example");
JButton button = new JButton("Press me");

public UsualJavaGui() {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Button pressed");
}
});
frame.add(button);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);

}

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {
public void run() {
new UsualJavaGui();
}
});

}
}

Now, the main problem people have with java is that it's overly verbose, and they're right in that aspect. CICE aims to reduce that verbosity; by making it more concise and to the point. Now you know the basics of that implementation; it's a simple JFrame with a button that when you click it will display a message in your console.

Now the same app but with CICE:

import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
* Created: Mar 19, 2008 5:57:45 PM
*
* @author Robert O'Connor
*/
public class CICEGui {
JFrame frame = new JFrame("CICE Gui");
JButton button = new JButton("Press me");

public CICEGui() {
button.addActionListener(ActionListener(ActionEvent e){
System.out.println("Button pressed");
});
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(Runnable() {
new CICEGui();
});
}
}


The above is a lot less verbose; What's missing? You'll notice the difference primarily in the main() method and the addActionListener() method call to attach the event listener to my JButton.
What's missing? That's right the
public void run() { ... }
and
public void actionPerformed(ActionEvent e) { ... }
How can this be and how do I get access to the ActionEvent reference? Well notice the following:
button.addActionListener(ActionListener(ActionEvent e) {
System.out.println("Button pressed");
});
I passed in the ActionEvent parameter to the Concise Instance Creation Expression! Using CICE, I was able to eliminate the methods. Also note, that I was able to eliminate using the word new is not needed with CICE. I was also able to state my intent cleanly, and in a lot less verbose way. How many lines were eliminated between the Java version and the CICE version?

(rob-laptop)rob@~/playground/src/main/java$ wc -l misc/UsualJavaGui.java misc/CICEGui.java
43 misc/UsualJavaGui.java
34 misc/CICEGui.java
77 total
(rob-laptop)rob@~/playground/src/main/java$

Well, that's 9 lines! Why should you have to type out the method definition if there is only ONE method in the interface or abstract class?

Groovy is kinda really groovy

public class StringTester { 
    public static void main(String[] args) {
        System.out.println(new String("foo") == "foo"); 
    }
}

Now the above code will evaluate to false. However if I changed it to:
"foo" == "foo"
it will be true. Reason: Java interns String literals. This is precisely why using == on String isn't advised. However groovy converts all == instances to .equals() so we basically get the same result as if we interned the String in java. This makes sense, since in groovy there are no primitive data types; it uses the wrapper classes from java. Integer, Double, Byte, etc. More information about the wrapper classes can be found here.
class StringTester { 
    static void main(args) {
        println new String("foo") == new String("foo") 
        println new String("foo") == "foo"
        println "foo" == "foo" 
    }
}

All three cases will evaluate to true. Now we can modify the java code so that it behaves the same way groovy did:

public class StringTester { 
    public static void main(String[] args) {
        System.out.println(new String("foo").intern() == "foo");
        System.out.println(new String("foo").intern() == new String("foo").intern()); 
    }
}

Now both will evaluate to true! Interesting thing =)

For more information about interned Strings check out this

Monday, March 17, 2008

Closures in java: Fibonacci gets some closure

So, in my previous post I promised an example; it's a simple example. In order to compile it you will need to download the BGGA prototype. You can run it using your installed jre. I'll fiddle with it some more but i wanted to put this one up, so here we go:

public class FibonacciSequenceWithClosures {
public static void main(String[] args) {
int fib = {int n => fib(n)}.invoke(Integer.parseInt(args[0]));
System.out.println(fib);
}

/**
* Helper method to recursively calculate the
* n-th number in the fibonacci seqeunce.
* @param n
* @return the n-th number
* @throws IllegalArgumentException if you pass in a negative number
*/
public static int fib(int n) {
if(n < 0) {
throw new IllegalArgumentException("Must be Postive!");
} else if(n == 1 || n==2) {
return 1;
} else {
return fib(n-1) + fib(n-2);
}
}
}



What's going on here? Let's examine it line by line. First you've got your familiar standard class definition; I declare a variable named fib, I'm sure you're asking the what the heck is
 int fib = {int n => fib(n)}.invoke(Integer.parseInt(args[0]));
Answer: it's a closure! We'll examine that line closer.
int fib = { int n => fib(n)}.invoke(Integer.parseInt(args[0]));
First, we have the parameters that we're passing into the closures, then you see
int fib = { int n => fib(n)}.invoke(Integer.parseInt(args[0]));
and you're probably wondering what in god's name that operator is, it's the closure operator! Now, the final piece:
int fib = { int n => fib(n)}.invoke(Integer.parseInt(args[0]));
What i'm doing here, is calling the invoke method on the closure itself, and passing in the first argument passed to the program via a command-line argument. Finally, After all this is done, I print the value returned from the closure that i stored in the variable fib and we're done. You'll get a StackOverFlowException if you pass too large a number. I could probably fix this, but this is sufficient for a simplistic example.

Closures in java

I have the tendency to come off as a real idiot sometimes; and I tend to evangelize anything that looks remotely cool; and that's true, but BGGA closures, looks interesting to me. However, after I watched Josh Bloch's The Closures Controversy [slides] a few weeks ago, I got very turned off. The latest prototype looks a little bit better. I'll fiddle with it and post the code I wrote up here. Once again, I've yet to play with it, but perhaps it's better? All I know is that the groovy-like syntax for the closure operator piques my interest.

Monday, February 18, 2008

Groovy isn't groovy when it comes to access modifiers in java

Last night, I was mucking around and noticed something odd -- Groovy ignores access modifiers of your class properties (members). What's worse is that it's known, and yet the developers and designers don't seem to wanna be bothered right now. Isn't that lovely?

Sunday, February 17, 2008

a Groovy Utility class :)

I wrote a Groovy utility class to help with setting Bindings for the GroovyShell. Additionally, I wrote a method that completely encapsulates the GroovyShell entirely.


import groovy.lang.Binding;
import groovy.lang.GroovyShell;

import org.codehaus.groovy.control.CompilationFailedException;


/**
* Created: Feb 17, 2008 3:31:44 PM
*
* @author Robert O'Connor
*/
public final class GroovyUtil {
/**
* Utility method to set up bindings.
*
* @param bind the string you're binding
* @param obj to bind to.
* @return the Binding object
*/
public static Binding bindTo(String bind, Object obj) {
Binding b = new Binding();
b.setVariable(bind, obj);
return b;
}

/**
* Utility method to get a shell with the specified binding
*
* @param bind the binding
* @return the shell instance.
*/
public static GroovyShell getShell(Binding bind) {
return new GroovyShell(bind);
}

/**
* Execute a Groovy script.
*
* @param bind binding String
* @param obj Object binding
* @param code script code.
* @throws CompilationFailedException if the compilation fails.
* @throws IllegalArgumentException if you do not specify the bindings.
*/
public static void exec(String bind, Object obj, String code)
throws CompilationFailedException {
if ((obj == null) || (bind == null) || bind.equals("")) {
throw new IllegalArgumentException("No binding specified.");
}

GroovyUtil.getShell(GroovyUtil.bindTo(bind, obj)).evaluate(code);
}
}

Wednesday, January 30, 2008

Jerkbot gets a Groovy makeover

Tonight I decided to rewrite my example bot for jerklib. I chose to do it in Groovy because i've had the urge to use it. The fact that it integrates well with java makes it a perfect candidate to write a bot (or even a client) using Jerklib! As I was writing it I felt like a kid in a candy store, oogling at the coolness that is Groovy. To run this code download the jerklib jar. Then simply type:
groovy -cp jerklib.jar:. filename.groovy
Or you're on windows then it's:
groovy -cp jerklib.jar;. filename.groovy

Of course you'll replace filename.groovy w/ the file you saved it under.

A Note: I primarily used this class to test my additions to the jerklib -- so you can call this a scratchpad of sorts (at least it was at the time.)


import jerklib.Profile
import jerklib.ProfileImpl
import jerklib.events.listeners.IRCEventListener
import jerklib.events.IRCEvent
import jerklib.events.JoinCompleteEvent
import jerklib.ConnectionManager
import jerklib.events.MessageEvent
import jerklib.events.MessageEvent
import jerklib.events.NickChangeEvent
import jerklib.events.AwayEvent



/**
* Created: Jan 29, 2008 11:42:23 PM
* @author Robert O'Connor
*/
class GroovyJerkbot implements IRCEventListener {
def manager

GroovyJerkbot(String nick, String username, String hostname, int port) {
def profile = new ProfileImpl(username, nick, nick + new Random().nextInt(42),
nick + new Random().nextInt(512))
manager = new ConnectionManager(profile)
manager.requestConnection(hostname, port).addIRCEventListener(this)

}


static void main(args) {
def bot = new GroovyJerkbot("jerkbot", "jerkbot", "irc.freenode.org", 6667)
}

@Override
void receiveEvent(IRCEvent e) {
if (e.getType() == IRCEvent.Type.CONNECT_COMPLETE) {
e.getSession().join("#jerklib")
e.getSession().who("mohadib")
e.getSession().setAway("FOO!")
}
else if (e.getType() == IRCEvent.Type.JOIN_COMPLETE) {
def JoinCompleteEvent event = (JoinCompleteEvent) e
event.getChannel().say("Hai2u")
} else if (e.getType() == IRCEvent.Type.CHANNEL_MESSAGE) {
MessageEvent event = (MessageEvent) e
// what does this is take the channel msg and match it to the pattern ~say foo
def matcher = event.getMessage() =~ /^~say\s+(.*)$/
if (matcher.matches())
{
e.getSession().channelSay(event.getChannel().getName(), matcher.group(1))
}else if(event.getMessage() ==~ /^~part.*$/) {
e.getSession().partChannel(event.getChannel(),"I was asked to leave")
} else {
def whoMatcher = event.getMessage() =~ /^~who\s+(.*)$/
if(whoMatcher.matches()) {
e.getSession().who(whoMatcher.group(1))
}
def awayMatcher = event.getMessage() =~ /^~away\s+(.*)$/
if(awayMatcher.matches()) {
e.getSession().setAway(m.group(1))
}else {
e.getSession().unsetAway()
}
}

} else if (e.getType() == IRCEvent.Type.PRIVATE_MESSAGE) {
MessageEvent event = (MessageEvent)e
if(event.getMessage() ==~ /^~quit.*$/) {
e.getSession().close("I was asked to leave.")
}
} else if (e.getType() == IRCEvent.Type.NICK_CHANGE) {
NickChangeEvent event = (NickChangeEvent) e
println event.getOldNick()
println event.getNewNick()
println event.getUserName()
println event.getHostName()
println e.getRawEventData()
} else {
if (e.getType() == IRCEvent.Type.AWAY_EVENT) {
AwayEvent event = (AwayEvent)e
println "Nick: "+event.getNick()
println "Event Type: "+event.getEventType()
println "Us?: "+event.isYou()
println "Away?: "+event.isAway()

}
}

}

}



As you can see, the import for Random is missing (no need with groovy, it's imported implicitly, whereas in java, only java.lang is imported implicitly! Also, semi-colons are OPTIONAL!! Groovy has native regex support! =~ means to create the matcher for this pattern. The ==~ operator checks if the text matches the pattern given after the ==~ operator.

Nobody would argue with me if I said the above example was verbose. Jason Davis wrote this the following gem:

 
import jerklib.*;
import jerklib.tasks.*;
import jerklib.events.listeners.*;
import jerklib.events.IRCEvent.Type;

def stratMap =[:]
stratMap[ Type.CONNECT_COMPLETE ] = {x-> x.session.joinChannel "#jerklib"}
stratMap[ Type.JOIN_COMPLETE ] = {x-> x.channel.say "Hello World"}
stratMap[Type.CHANNEL_MESSAGE] = {x-> println x.rawEventData}

conMan = new ConnectionManager(new ProfileImpl("foo","gscripbot","gscripbot1","teh"));
session = conMan.requestConnection('irc.freenode.net');
session.addIRCEventListener({x-> close = stratMap[x.type]; if(close != null)close(x)} as IRCEventListener);


Jason used the Strategy Pattern for the event handling. It cleans up your code greatly and eliminates the need for a bunch of if statements. It also can cut down on the verbosity of your code, like it has in this case.