Recently by Chris Rohr

Groovier Processing

| | Comments (1) | TrackBacks (0)

Introduction

Processing is a basically a proprietary Java-like language compiled into Java bytecode and used for generating dynamic and interactive data visualizations. Though still in its infancy, it seems to be a very nice intuitive way to build visualizations of data into an application. The download for Processing contains the compiler, library and an editor. The file format for Processing files is .pde. Inside of these files you can treat the language just like a scripting language. For instance:

size(400,400);
background(192, 64, 0);
stroke(255);
line(150, 25, 270, 350);

This block of code is from the book "Visualizing Data" by Ben Fry and will just set the window size, set the background color, set the line color and draw a line. The output will look like:

There are 2 methods that processing will look for to do initial setup and then the refreshing of the canvas. Adding those methods and adding some mouse interaction we get the following code:

void setup() {
   size(400, 400);
   stroke(255);
   background(192, 64, 0);
}

void draw() { line(150, 25, mouseX, mouseY); }
The output from this block of code will look like:



There are a lot more convenient functions and properties available when using the Processing API but that will have to wait for another blog. The editor that comes with Processing is functional, but is lacking in features that many of the more modern editors contain. So I wanted to try and see if I could use my standard editor and still build Processing apps.

Eclipsing the IDEA

Processing so nicely comes with a jar core.jar. This jar then can be added to a project in the editor of your choosing. Once you are in Java world there are couple of things that need to change with your Processing code. Mainly you have to now adhere to Java programming rules. Our code from above in the Java world would look like the following:

import processing.core.PApplet;

public class BlogExample extends PApplet { public void setup() { size(400, 400); stroke(255); background(192, 64, 0); }

public void draw() { line(150, 25, mouseX, mouseY); } }
As you can see, the code becomes a little lengthier. We need to add all of the modifiers on and the class definition and all of that, but we are at least in the IDE of our choice now and can just run this file and get the same output as the Processing editor. Now lets say we we want to add boxes to our output. We can add a class called Box to the project (Processing editor supports multiple classes as well). The code for the Box class would be:
public class Box {
    private String title;
    private String boxText;
    private int width;
    private int height;
    private String backgroundColor;
    private String textColor;

public int getWidth() { return width; }

public void setWidth(int width) { this.width = width; }

public String getTitle() { return title; }

public void setTitle(String title) { this.title = title; }

public String getBoxText() { return boxText; }

public void setBoxText(String boxText) { this.boxText = boxText; }

public int getHeight() { return height; }

public void setHeight(int height) { this.height = height; }

public String getBackgroundColor() { return backgroundColor; }

public void setBackgroundColor(String backgroundColor) { this.backgroundColor = backgroundColor; }

public String getTextColor() { return textColor; }

public void setTextColor(String textColor) { this.textColor = textColor; } }
Then we add some code to our main class to use the Box.
public class BlogExample extends PApplet {
    public void setup() {
        size(400, 400);
        stroke(255);
        background(192, 64, 0);
    }

public void draw() { line(150, 25, mouseX, mouseY); List boxes = getBoxes(); int xPos = 0; int yPos = 0; for (Box box : boxes) { drawBox(box, xPos, yPos); xPos += box.getWidth() + 5; yPos += box.getHeight() + 5; } } private void drawBox(Box box, int xPos, int yPos) { //Draw the box on the screen; }

private List getBoxes() { List boxes = new ArrayList(); Box box = new Box(); box.setTitle("Box 1"); box.setBoxText("Text in Box 1"); box.setBackgroundColor("blue"); box.setTextColor("white"); box.setWidth(100); box.setHeight(100); boxes.add(box); //Add more boxes here return boxes; }
}
Now you can see we have added a lot of code to do some simple processing of boxes. This isn't very script-like anymore. I was thinking of how to get this code base a little smaller. I then thought of what would happen if I added Groovy to it.

Groovifing the Code

After adding the groovy jar, I could change my .java files to .groovy files and start shrinking the code base. Here is what the above code became:

class BlogExample extends PApplet {
    void setup() {
        size(400, 400)
        stroke(255)
        background(192, 64, 0)
    }

void draw() { line(150, 25, mouseX, mouseY) def boxes = getBoxes()

def xPos = 0 def yPos = 0; boxes.each {box -> drawBox(box, xPos, yPos); xPos += box.width + 5; yPos += box.height + 5; } }

private void drawBox(def box, def xPos, def yPos) { //Draw the box on the screen; }

private List getBoxes() { return [ new Box(title:"Box 1", boxText:"Text in Box 1", backgroundColor:'blue', textColor:'white', height:100, width:100) //Add more boxes here ] } }

class Box { String title; String boxText; int width; int height; String backgroundColor; String textColor; }


Making the code a little Groovier has reduced the amount of lines that I need to write to get my visualization up and running. So now I've got the simpler syntax of a scripting language and all the power of my IDE and all of my Java libraries. I know that this example is very primitive and you don't necessarily get as much bang for your buck on something this small, however, as this application grows into something bigger the gains will become more apparent.

The Not-So-SimpleDateFormatter

| | Comments (0) | TrackBacks (0)
This posting is Part 1 of 2 related to using Dates in Java webapps.

Problem

Your application has a form with a date entry on it. This entry needs to allow multiple formats and perform some basic date validation on the input. Valid formats allowed are:

  • MM/dd/yyyy
  • MM/yyyy
  • yyyy
  • ddMMMyyyy
  • MMyyyy

Solution #1

The first attempt of solving this problem was to write a custom parser that did a whole bunch of checking on string lengths and splits based on certain cases (ie. slashes and spaces).

Example code

public boolean isValidDate(String dateStr) {
	switch(dateStr.length()) {
		case 4:
			//Is a year
			//Check to see if valid year
		case 7:
			if (dateStr.indexOf('/') > 0) {
				//Is MM/yyyy
				//Check to see if valid month and year
			} else {
				//Is MMMyyyy
				//Check to see if valid month and year
			}
		case 9:
			//Is ddMMMyyyy
			//Check to see if valid day, month and year
		case 10:
			//Is MM/dd/yyyy
			//Check to see if valid day, month and year
		default:
			return false;				
	}		
}

Outcome

This solution proved to be problematic for a number of reasons. First, it caused a lot of ugly code to be written. I think the cyclomatic complexity was about 15 and the code made up of at least 60-70 lines of code. Second, it was very error prone. There were a couple different iterations where every case was handled and then was found not to be true (sometimes found by real users!).

Solution #2

After about 5 tries of getting the date validation correct, a new approach was taken. The date string was parsed using the java.lang.text.SimpleDateFormatter and then passed into a java.util.Calendar object. The parts that made up the date were then verified against the original string to make sure they were the same. The reason for using the java.util.Calendar object is because by default the java.lang.text.SimpleDateFormatter is very lenient when it comes to parsing. If the date 13/25/2007 is passed in, it will return a java.util.Date object but with the date Jan. 25th, 2008.

Example code

public boolean isValidDate(String dateStr, String...formats) {
	for (String format : formats) {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(format);
			Date parsedDate = sdf.parse(dateStr);
			
			Calendar cal = Calendar.getInstance();
			cal.clear();
			cal.setTime(parsedDate);
			
			//Get year from dateStr  (requires figuring out the parts of the date based on the format)
			//Does the year values equal each other?
			
			//Get month from dateStr 
			//Does the month values equal each other?
			
			//Get day from dateStr
			//Does the day values equal each other?
			
		} catch (ParseException e) {
			//Not a valid date based on format
		}
	}
	
	return false;
}

Outcome

This solution handled all of the cases that were problematic in Solution #1. The code base was slimmed down some but it was still a lot of logic for parsing a simple date including still having to figure out the date parts. Also, for date validation we didn't want the validator to "fix" the date for us.

Solution #3

We then needed to find a way to further slim down our code. A coworker then found that the java.lang.text.SimpleDateFormatter had a setter for leniency. By setting this to false, the parser will not accept 13/25/2007 as a valid date. Note: We couldn't just use the org.apache.commons.lang.DateUtils.parseDate(String str, String[] parsePatterns) to parse the date. That method keeps the leniency as true, leaving us in the same state we were before.

Example Code

public boolean isValidDate(String dateStr, String...formats) {
	for (String format : formats) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		sdf.setLenient(false);
		try {
			sdf.parse(dateStr);
			return true;
		} catch (ParseException e) {
			//Ignore because its not the right format.
		}
	}
	return false;
}

Outcome

This piece of code was a very simple, clean solution to the problem. However, there was one issue that crept into this example. If I made the call isValidDate("25BAD2007", "MM/dd/yyyy", "MM/yyyy", "yyyy", "ddMMMyyyy", "MMMyyyy") the return value would be true. The reason for this is because even though the date had more than just a year, the 2007 part passed yyyy. The only solution to this issue that I have been able to come up with is to add some logic outside of the isValidDate method that quickly determines the formats to pass in. Though this seems like the parsing logic was just moved from inside the method to out, it is actually less logic in the long run. Here is the example to call the isValidDate method:

boolean validDate = false;
if (dateStr.length() == 4) {
	validDate = isValidDate(dateStr, "yyyy");
} else if (dateStr.indexOf('/') > 0) {
	validDate = isValidDate(dateStr, "MM/dd/yyyy", "MM/yyyy");
} else {
	validDate = isValidDate(dateStr, "ddMMMyyyy", "MMMyyyy");
}

Summary

The moral of the story is Date validation is hard when multiple formats are allowed. Beware of what SimpleDateFormat is actually doing; You may be getting different results than expected because the parsing didn't fail.