sreda, 7. september 2011

Creating java commmand line programs hell

Let's say you need to create quick command line program in java, to process 10000 folders with some xml files in it. You can do it in java of course. If you run it from your IDE, cool no problems. But if you want to run this on some other machine, let's say linux, and you have additional jars and you do not have debugger on that machine you quickly end up in few days of real hell.

There is a really very quick workaround for this, it'c called Groovy. Groovy let's you do that:

  • use your existing java code
  • use your existing classpath libraries
  • allows you to write in pure java
  • allows you to change script's on the fly
  • allows you to work with source only, no precompilation, recompilation
  • you can add debug statements on the fly
Sounds like heaven? Well, it is. Look at example below, where is some stupid routine to traverse one root folder and output sub folder names. I't uses existing java code from original java projects, and it runs from command line with all the pros from before.

package com.antaranga.groovy.utils

import java.util.Hashtable;
import java.io.File;
import java.lang.annotation.ElementType;
import java.math.SignedMutableBigInteger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.util.Date;

class Cleanup {

static main(args) {
boolean dryRun = false;
String rootFolder = "c:\\root";
System.out.println(String.format("Start processing folder %s , readonlyMode =  %s.", rootFolder, dryRun));
Cleanup c = new Cleanup();
List<DirectoryWalkerStruct> workFolderList = c.walkin(new File(rootFolder));
for (DirectoryWalkerStruct myDir : workFolderList){
System.out.println("Folder found: " + myDir.directoryName);
}
System.out.println("End.");
}

//**************  Function below are copy paste from existing java code
private List<DirectoryWalkerStruct> walkin(File dir) {
List<DirectoryWalkerStruct> workFolderList = new ArrayList<DirectoryWalkerStruct>();
File[] listFile = dir.listFiles();
if(listFile != null) {
for (File f : listFile) {
if(f.isDirectory()) {
workFolderList.add(new DirectoryWalkerStruct(f.getName(), f.getAbsolutePath(), new Date(f.lastModified())));
}
}
}
return workFolderList;
}
class DirectoryWalkerStruct {
private String directoryName;
private String fullPath;
private Date lastModified;
public DirectoryWalkerStruct(String directoryName, String fullPath, Date lastModified) {
super();
this.directoryName = directoryName;
this.fullPath = fullPath;
this.lastModified = lastModified;
}
public String getDirectoryName() {
return directoryName;
}
public void setDirectoryName(String directoryName) {
this.directoryName = directoryName;
}
public String getFullPath() {
return fullPath;
}
public void setFullPath(String fullPath) {
this.fullPath = fullPath;
}
public Date getLastModified() {
return lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
}
}

You need to read some xml?

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document xmlRootDoc = builder.parse( new File( xmlPath ) );

//get the <root> nodes
Node rootNode = xmlRootDoc.getChildNodes().item(0); 

//get the first level elements 
NodeList childNodes = rootNode.getChildNodes();

//get element
Element firstElement = (Element) childNodes.item(0);
String firstAtt = firstElement .getAttribute("someAtt");

One of the most platforms is Grails (web framework based on groovy), with all the java stuff + grails stuff, and possibility to use grails code as a java beans (JSF, JSP, EJB).

Let's hope you can quickly crawly out from this hell  (just to fall into another one next time).



torek, 6. september 2011

Resolving Java Exception Hell

Resolving Java Exception Hell

Consider following java exception hell:

public class Utils {
public void processFile(String filename) throws IOException {
        try {
            FileOutputStream fos = new FileOutputStream(filename);
//do something with file
        }
        catch (IOException ex) {
  //make some logging  and exception handling
throw new IOException(ex.getMessage());
        }
    }
}
public class FileProcesser {
public void processSomeFile(String filename) throws IOException {
        try {
Utils u = new Utils();
u.processFile("myFile.txt");
        }
        catch (IOException ex) {
  //catch the exception thrown from utils class
//log here also??
throw new IOException(ex.getMessage());
        }
    }
}

public class Program {
public static void main(String[] args) {
try {
FileProcesser p = new FileProcesser();
p.processSomeFile(args[0]);
}
catch (IOException ex) {
//catch the exception thrown from utils class
//log here also??
throw new IOException(ex.getMessage());
}
}
}



Here we have 3 classes, namely Utils, Fileprocessor, Program. One uses another. Obvisously, the smallest working unit, which does the actual work, can of course fall into exception (which is very normal). But see how the code becomes polluted by that exception. You're passing it to the top calling class. And you can fall into endless artistical design debates on where to the the logging etc. Now image ourself changing exception type or adding addition exception. If you have 10 usages of Utils class in 2 level approach (as in this sample), you will end up with extensive refactorings. 


Now is there any way to get out of this hell? It is... And the solution has name:  RuntimeException. The beauty of runtime exception is, that you need NOT to declare it with throws. Thus, you handle exception where it happens, and write a code in a most logical way.


public class Utils {
public void processFile(String filename) {
        try {
            FileOutputStream fos = new FileOutputStream(filename);
//do something with file
        }
        catch (Throwable ex) {
  //make some logging  and exception handling
throw new RuntimeException(e);
        }
    }
}
public class FileProcesser {
public void processSomeFile(String filename) {
Utils u = new Utils();
u.processFile("myFile.txt");
    }
}
public class Program {
public static void main(String[] args) {
FileProcesser p = new FileProcesser();
p.processSomeFile(args[0]);
}
}

Of course there are hidden implications of this design. Most important point is, that unlike the previous example, the code of this program will stop running. In web application for example, the rendering of the page will stop, and you will most likely redirect to error page. So this solution is best suitable for the cases where you want to stop the execution of a program, if something goes wrong. Which in my case is the best approach. Exceptions are basically of these kinds:

  • formal validation exception (like date not entered). This is actually warning to user
  • fatal exception (you cannot proceede, and you DON'T WANT to proceede)
  • really unexpected exception (you also want your app to crash)
I believe, that it is more important to notice that something went wrong, then trying to hide that. If programs eats the exception, and makes you think everything is cool, this is more a politician way. 

Additional upgrade to solution would be to introduce your own custom excpetion type  (Do not have more than one custom exception in application or it will result in - hell!):

public class FatalException extends RuntimeException {
String desc = "";
public FatalException(String desc, Throwable reason) {
super(reason);
this.desc = desc;
}
private void logEx() {
//super.reason.printStackTrace
}
}

usage: throw new FatalException (e);

With this custom exception, you have one place only in your app, where you handle the exception, do the logging, process exception text, notify user or whatever you need. This will significantly improve your consistency and reduce the amount of code.

You can even query the exception type here:

//Throwable reason; 

if (reason instanceof JAXBException) {
//log
}
else if(reason instanceof IOException) {
//send mail
}
else if(reason instanceof LoginException) {
//log to database
}
else{
//redirect
}

I hope this will help you on your stair way to programming heavens.