Thursday, September 29, 2011

Ant Build System: An XML version of make

Once upon a time, I tried to practice Java by typing up my codes in vim on the terminal and running it there.  The problem?  I couldn't.  Java has gotten a bit more complicated than what I remembered.  Instead of a welcoming "Hello World", I get thrown an exception: java.lang.ClassNotFoundException.  That's just not friendly, especially for someone who's just trying to say hello!

Thus, I have been sticking with the eclipse IDE ever since.  It feels a bit handicapped, since I can't automate things on the terminal and use command-line programs such as make.  However, it was necessary to build my basic Java knowledge in a simple IDE before trying to tackle more advanced topics.  Luckily, we didn't have to wait long to learn about the Java-version of make and other automation tools: the Ant build system.

Ant is invoked on the terminal using the command 'ant', and by default, looks for an "XML makefile" named 'build.xml'.  To tell it to use other script file, you need to invoke it in this form: 'ant -f <script-file>'.  Today, we'll look at some sample XML script files to familiarize ourselves with ant:

1. A simple Hello World

<project name="HelloWorld" default="helloworld" basedir=".">
<target name="helloworld" description="print out Hello World">
<echo message="Hello World" />
</target>
</project>

The code above illustrates the minimally required XML elements for an ant script.  First, the 'project' tag define the project name and indicate the default target to execute.  In this case, we only have one 'target' in this script, and it's named "helloworld" and is the default target.  Within the "helloworld" target, a single 'echo' command is embedded to print out "Hello World" when the script is invoked by ant.

2. Immutable Properties

<project name="ImmutableProperties" default="printproperty" basedir=".">
<property name="my.property" value="1"/>
<property name="my.property" value="2"/>
<target name="printproperty" description="print out the value of the property my.property">
<echo>Value of my.property is: ${my.property}</echo>
</target>
</project>

The code above illustrates a new tag called 'property', which is used to define something similar to a named constant.  However, the catch is that properties are immutable, and thus the second definition of property named "my.property" is ignored.  The 'echo' line illustrates how one may access the value stored in a property, by enclosing it in the form: '${<property-name>}'.

3. Dependencies

<project name="Dependencies" default="foo" basedir=".">
<target name="foo" depends="bar">
<echo>foo</echo>
</target>
<target name="bar" depends="baz,elmo">
<echo>bar</echo>
</target>
<target name="baz" depends="qux">
<echo>baz</echo>
</target>
<target name="qux" depends="elmo">
<echo>qux</echo>
</target>
<target name="elmo">
<echo>elmo</echo>
</target>
</project>

The good old makefile had the ability to define dependencies and automate a whole hierarchy of dependent tasks.  The ant-version of that is similar, and uses the 'depends' keyword in the 'target' element definition.  The code above illustrates its use:
(a) by default, "foo" is the target, but because it depends on "bar", "bar" is executed first
(b) however, "bar" depends on two other targets, "baz" and "elmo", in that order
(c) "baz" yet again depends on another target named "qux"
(d) and "qux" depends on "elmo"
(f) finally, "elmo" doesn't depend on anything else, so it executes its content.  The dependencies is fulfilled, and the code unraveled back up the chain.
The final outputs are: "elmo", "qux", "baz", "bar", "foo", in that order.

4. Java Compilation using javac

<project name="HelloAnt" default="compile" basedir=".">
<property name="src.dir" location="src" />
<property name="build.dir" location="build" />
<target name="compile">
<mkdir dir="${build.dir}/classes" />
<javac srcdir="${src.dir}" destdir="${build.dir}/classes" includeAntRuntime="false" />
</target>
<target name="clean">
<delete dir="${build.dir}" />
</target>
</project>

Finally, we get to do the cool stuff: automating the build of your Java project.  The interesting thing to note here is this: if you named your package correctly, and placed the files in the correct package hierarchy within your "src" directory, all the codes are compiled automatically with a single ant command: 'javac'.  In the code above, we want to organize the compiled *.class files within the "build/classes" subdirectory, so we create that directory with the 'mkdir' command, and then tell 'javac' to use it as the "destdir".  A single line to compile your whole source tree, now that's an improvement over make!

Another target that's normally found in the makefile is "clean".  Luckily, because we generate our build within the "build" subdirectory, the cleaning task is simple.  Whenever the "clean" target is invoked (i.e. with 'ant -f compile.helloant.build.xml clean') the 'delete' command is executed on the "build" directory.

5. Java Execution using java

<project name="HelloAntExecute" default="run" basedir=".">
<import file="compile.helloant.build.xml"/>
<target name="run" depends="compile">
<java classname="edu.hawaii.ics613.helloant.HelloAnt" classpath="${build.dir}/classes" fork="true" />
</target>
</project>

So, we are back to the original question: how do you run a Java program once you get it to compile, without throwing java.lang.ClassNotFoundException, on the terminal?  It turns out that due to the hierarchy of the packaging of Java classes, you can't expect 'java' to take a direct path to the *.class file and execute it.  Instead, you need to invoke it with the full package name and provide it the class path to where the package was compiled to.  For example, assuming the build script places its compiled classes in the "build/classes" subdirectory, then you would execute them manually by typing:
    java -classpath build/classes <full-packaged-class-name>
In the code example above, we have a class named "HelloAnt" within the package "edu.hawaii.ics613.helloant", thus the full packaged class name is "edu.hawaii.ics613.helloant.HelloAnt".  The 'java' element line illustrates how the respective pieces normally required on the command line is provided to the 'java' command in the XML script.  You might have noticed that the property "build.dir" was not declared anywhere in this script.  This is because it is imported from the previous script using the 'import' syntax.

6. Java Documentation using javadoc

<project name="HelloAntDoc" default="javadoc" basedir=".">
<import file="compile.helloant.build.xml"/>
<target name="javadoc" depends="compile">
<mkdir dir="${build.dir}/javadoc" />
<javadoc sourcepath="${src.dir}"
destdir="${build.dir}/javadoc"
author="true"
version="true"
use="true"
package="true"
overview="${src.dir}/overview.html"
windowtitle="HelloAnt API"
doctitle="HelloAnt API"
failonerror="${javadoc.failonerror}"
linksource="true" />
</target>
</project>

The normal 'javadoc' documentation is generated in a similar fashion.  For more details on the syntax used, see the full documentation of 'javadoc': http://ant.apache.org/manual/Tasks/javadoc.html

7. Zip it up

<project name="HelloAntDist" default="dist" basedir=".">
<import file="javadoc.helloant.build.xml"/>
<import file="run.helloant.build.xml"/>
<property name="dist.name" value="ant-code-katas-toyl" />
<property name="dist.dir" location="${build.dir}/dist" />
<target name="dist" depends="compile,run,javadoc,clean">
<zip destfile="${dist.dir}/${dist.name}.zip">
<zipfileset dir="${basedir}" excludes="*.jar, lib/**, javadoc/**, bin/**, **/.svn/*, **/*~, tmp/**, build/**" prefix="${dist.name}" />
</zip>
</target>
</project>

The last step in an automated build system is the ability to package up the codes, after testing that it works, into a distributable archive.  In the code above, we used the 'zip' command.  The syntax is a bit more complicated due to our need to make the archive contain the project folder hierarchy.  To do so, you need to specify the "prefix" attribute of the 'zipfileset' element.  Packaged in this way, the archive will recreate a single folder specified by the "prefix" containing the whole project tree.

In conclusion, 'ant' is the Java-version of make.  It is a bit verbose due to its XML syntax.  However, it is still a good price to pay in gaining back the automation capability of a build system.

Tuesday, September 20, 2011

Gaming Challenge: Robocode!


Last Sunday, I spent 16 hours porting the memory scanner from Cheat Engine to a scripting language I use in windows for gaming automation purposes.  Yup, 16 hours!  I guess something clicked in my dream, and I woke up at 1AM and kept cracking at it for 16 hours straight!  Tired?  Not really.  It was fun!

FUN is the keyword.  If it's fun, I don't mind doing it more often.  Heck, if it's fun, I WANT to do it ALL the time!  The difference between being mentally tired from an 8-hour day-job, and being mentally enlightened from a 16-hour "hack and crack" is your attitude... and "Fun" is definitely the right attitude to have!

So, how about having FUN in an ICS programming assignment?  Sure!  The screenshot above is what we are doing in our ICS 613 class.  Nope, we are not designing a game from scratch.  Instead, we are competing in a robotic challenge called the Robocode.

Robocode is a Java-based competition arena for anyone interested in putting their minds and wits to the test.  The challenge?  Program your own robots and put your robots' intelligence to the test by competing against other robots.  The catch?  You need some Java know-how, be creative, and most definitely, time, to have fun!

The most challenging part of Robocode for me was trigonometry.  Yes, you need MATH to play smart!  In fact, all the good game engines out there uses Physics and lots of Math.  It was an interesting and refreshing experience to see programmers pulling out their pencils and scrible away on a sheet of paper instead of typing up codes.  I guess sometimes we forget: good software are designed and engineered.  Sometimes the  engineering notes all reside on the programmer's head (the easy ones).  But most of the time, programmers need scratch paper too.

Additional Links: