jump to navigation

Ant, dependencies, and slow servers January 26, 2009

Posted by Phill in General J2EE.
Tags: , ,
comments closed

At work I’m working on an application which uses an Apache Ant script to build it. Unfortunately we haven’t yet got around to using Apache Ivy, however all dependencies are stored in a text file and then downloaded from a central server in the build script. Not an ideal solution but it works for our needs.

The problem comes when the central server we use to store the JAR files slows down to a crawl (which has happened quite a lot recently). The past few days, the build script has taken over 4 minutes to complete – and most of that time is spent downloading JAR files (unfortunately there are two JAR files which needed to be downloaded each time – it’s too complicated to go into now…)! So I decided to make a change to the build script.

Now, it should only download when I update the text file with the list of dependencies. How is this accomplished? By using the <condition> task:

<condition property="lib.uptodate">
<uptodate srcfile="${basedir}/lib-jarlist" targetfile="${lib.dir}/lastupdated.txt" />
<uptodate srcfile="${basedir}/lib-jarlist-compile-only" targetfile="${lib.dir}/lastupdated.txt" />

What this code is doing is checking two files (lib-jarlist and lib-jarlist-compile-only). If either of these two files have a newer timestamp than the target file (lastupdated.txt), than the condition will be TRUE. Then, all I need to do is put this in the download dependencies target:

<target name="download-deps" unless="lib.uptodate">
(download dependencies....)
<touch file="${lib}/uptodate.txt">

So, the target will only run if one of the JAR list files have been updated. Note the touch command at the end – this is important: it updates the file timestamp so that next time the script will see the update dependencies and not go off to the slow server for them.

It’s not a perfect solution, but will do until we can move to Ivy!


Code Coverage with Cobertura and JUnit June 3, 2008

Posted by Phill in Testing.
Tags: , ,
comments closed

I hadn’t used code coverage tools much before today. However, after getting to grips with Cobertura, I think I’m a convert!

What I’d like to do here is give a brief overview of what code coverage is, why you would want to use it, and how you can get up and running with code coverage tools in your own projects.

What is Code Coverage?

A Code Coverage tool, in the context of unit testing, basically tells you how much of your code is executing while the tests are running. So, for example, if you have 50 class files and have unit tests for all of them, the Cobertura will tell you how many lines of code per class you are “covering”.

In other words, it tells you how effective your unit tests are – whether you are hitting all the different execution paths through your code in your unit tests. You will probably find that your unit tests are, in fact, missing out various bits of code.

Why should I use it?

Following on from the previous paragraph, it helps you to cover all of your code with unit tests (or at least, all the bits of it which are unit-testable!)

If you can be sure that your unit tests are executing more of your code, you can have greater confidence in your unit tests. Although code coverage tools don’t tell you whether you are executing a method with every single different combination of parameters (and, let’s face it, that would be virtually impossible!) they do at least tell you that you’ve covered all the different methods etc. in your code.

In other words, it’s just a form of QA for your code, a complement to unit tests!

How do I get started?

A good start would be to download Cobertura and get started reading the documentation.

If you use Ant or Maven (if you’re still using your IDE to build your projects, you really should switch!) it’s fairly easy to integrate Cobertura into your project.

There’s only one little “gotcha” I came across: Cobertura would throw a “NoClassDefFoundError” about org/apache/log4j/Category.

It turned out that I was only provided a link to the cobertura.jar file in my <taskdef> tag, I actually need to include a reference to all required libraries in the <taskdef>.

Other than that, it’s been fairly plain sailing so far!

Starting and Stopping Tomcat from Ant April 14, 2008

Posted by Phill in Application Servers.
Tags: , , , ,
comments closed

One issue I have with Tomcat is that it doesn’t always undeploy an application cleanly. Sometimes it leaves a few .jar files in the WEB-INF/lib folder. I don’t know if there is any way around this, however it is inconvenient because it means every time I want to redeploy an application I’m working on at the moment I need to restart Tomcat.

Anyway, I’ve found an easy way of restarting Tomcat from within an Ant script – although unfortunately it only works on Windows! If you have Tomcat configured to run as a service, just drop the following into your build.xml:

<target name="tomcat-start">
	<echo>Starting Tomcat</echo>

	<exec executable="net">
		<arg value="start" />
		<arg value="${tomcat.service.name}" />

<target name="tomcat-stop">
	<echo>Stopping Tomcat</echo>

	<exec executable="net">
		<arg value="stop" />
		<arg value="${tomcat.service.name}" />

Note: you will need to have the property tomcat.service.name defined elsewhere – on my system the property value is “Apache Tomcat”.

Then, when you want to deploy a .war file to Tomcat, you just need to use <antcall target=”tomcat-stop”/> and <antcall target=”tomcat-start”/> at the start and end of your deploy target respectively. I also added in a “<delete dir =”tomcat-webapp-dir/app-name” /> after Tomcat was stopped just to be on the safe side – this may not be necessary though.

Building with Ant and Ivy March 31, 2008

Posted by Phill in General J2EE.
Tags: , , ,
comments closed

At one of my previous workplaces we used to use Maven for our build system, along with Cruise Control.  It was a pretty good system – Maven worked quite well and did all of our dependency management without any problems.

In case you haven’t heard about Maven before, let me quickly explain one of the key benefits of it: you define all the dependencies of a project in an XML file (pom.xml), and during the build process Maven will go and download all the required .jar files for you to use in the build. (Obviously, it caches them so it only downloads the ones you don’t already have!). This is a simplification (Maven can do more), but you get the gist.

If I was starting a “green fields” project, Maven would be a good choice.

Having said that, if you’re already using a project and want the benefits of dependency resolution, or you’re starting a new project and want dependency resolution along with the flexibility of Ant, let me introduce you to an Ant sub-project: Ivy. It’s also a dependency resolution framework, except that it runs from within the Ant build process.  From my experimentations with it, it seems to run out-of-the-box with the Maven repository, and the dependency configuration is very similar.

But there are some very useful things Ivy has which Maven doesn’t, for example you can define a configuration for Oracle and a configuration for SQL Server, and the various .jar files will be included / excluded accordingly.

The Ivy project have a helpful comparison page listing some of the differences between Ivy and Maven 2.

There are a few downsides to dependency resolution, but I will hopefully cover those in a future article!

Cruise Control and Ant problems February 5, 2008

Posted by Phill in General J2EE.
Tags: , , ,
comments closed

I had a really weird problem with Cruise Control / ant today. It was coming out with an error like this:

2008-02-05 10:48:27,903 [Thread-79] WARN ScriptRunner - java.lang.RuntimeException
2008-02-05 10:48:27,904 [Thread-79] WARN ScriptRunner - at org.apache.tools.ant.Main.createLogger(ant-1.6.5.jar.so)
2008-02-05 10:48:27,904 [Thread-79] WARN ScriptRunner - at org.apache.tools.ant.Main.addBuildListeners(ant-1.6.5.jar.so)
2008-02-05 10:48:27,904 [Thread-79] WARN ScriptRunner - at org.apache.tools.ant.Main.runBuild(ant-1.6.5.jar.so)
2008-02-05 10:48:27,905 [Thread-79] WARN ScriptRunner - at org.apache.tools.ant.Main.startAnt(ant-1.6.5.jar.so)
2008-02-05 10:48:27,905 [Thread-79] WARN ScriptRunner - at org.apache.tools.ant.launch.Launcher.run(ant-launcher-1.6.5.jar.so)
2008-02-05 10:48:27,905 [Thread-79] WARN ScriptRunner - at org.apache.tools.ant.launch.Launcher.main(ant-launcher-1.6.5.jar.so)
2008-02-05 10:48:27,913 [Thread-76] INFO Project - Project xxx: idle
2008-02-05 10:48:27,913 [Thread-76] INFO ProjectController - xxxController: build progress event: idle
2008-02-05 10:48:27,913 [Thread-76] ERROR Project - exception attempting build in project xxx
net.sourceforge.cruisecontrol.CruiseControlException: ant logfile /usr/share/cruisecontrol/projects/xxx/log.xml does not exist.
at net.sourceforge.cruisecontrol.builders.AntBuilder.getAntLogAsElement(AntBuilder.java:388)
at net.sourceforge.cruisecontrol.builders.AntBuilder.build(AntBuilder.java:198)
at net.sourceforge.cruisecontrol.Schedule.build(Schedule.java:165)
at net.sourceforge.cruisecontrol.Project.build(Project.java:226)
at net.sourceforge.cruisecontrol.Project.execute(Project.java:149)
at net.sourceforge.cruisecontrol.ProjectConfig.execute(ProjectConfig.java:369)
at net.sourceforge.cruisecontrol.ProjectWrapper.run(ProjectWrapper.java:69)
at java.lang.Thread.run(Thread.java:534)

Aaaanyway. The cause of this turned out to be that I already had a version of Ant installed (1.6.5), using a CentOS RPM, which meant that the version deployed with Cruise Control (1.7.0) wasn’t actually running. I have no idea why that was, but removing the CentOS RPM seemed to work! I think it might have been something to do with using the native library (the ant-1.6.5.jar.so should have given it away really…)

Just another one of those ‘gotchas’ which might help someone else waste time trying to figure it out…

Setting up Cruise Control November 8, 2007

Posted by Phill in Tutorials.
Tags: , , ,
comments closed

In a strange coincidence, after last week’s blog post about building applications using a continuous integration tool, the past couple of days I’ve been setting up a new instance of Cruise Control.

So, I thought I would use the opportunity to write a quick guide on installing Cruise Control and setting it up with a Subversion-based project. When I say “quick guide”, I basically mean explaining a few of the problems that I came across – not a comprehensive guide going through every step of the process!

Firstly, you need to download and install Cruise Control. I was installing it on CentOS (Linux), so I used the cruisecontrol-bin-2.7.1.zip. Installation is fairly simple, just unzip the archive somewhere – see the ‘Getting Started‘ page for details.

Note: Cruise Control, on Linux at least, expects an environment variable “JAVA_HOME” to be set up. You may need to add this into cruisecontrol.sh or your .profile file so that you don’t have to set it each time you run Cruise Control.

Secondly, you need to set up a project. Cruise Control comes with an example already set up, so I won’t go into the details of what exactly you need to do. However, there are a few things that caught me out:

  • The svnbootstrapper’s purpose is not to update the working copy from the repository. Its purpose is to update (for example) a build ant script from the repository so that you always build using the latest version. More on that later (see cc-build.xml).
  • If your Subversion repository is not set up for anonymous access, you will need to modify the provided configuration example to include a username and password both for <svnbootstrapper…> and <svn localWorkingCopy…>.
  • You will need to write a new ant script to update your local working copy from the repository. Create a new ant script and name it something like cc-build.xml, and copy and paste the following into it:
<project name="Project" default="cc-build" basedir="." >
	<property name="base.dir" value="." />
	<import file="build.xml" />
	<target name="cc-build" depends="update-src" description="Cruise Control Build">
		<antcall target="build" />
	<target name="update-src">
		<echo>Updating source from Subversion</echo>
		<exec executable="svn" dir="${base.dir}">
			<arg line="up" />

Then, what you need to do is modify your <schedule…> task as follows:

<schedule interval="300">
	<ant anthome="apache-ant-1.7.0" buildfile="projects/${project.name}/cc-build.xml" />

What does this do? Well, let’s assume your project uses an ant build script, called build.xml. The cc-build.xml imports this file, and then will update the repository to the working copy (the update-src task), and then will call the “build” target in the build.xml file.

Note: the “svn” command line client will need to be available from your PATH.

So, once you’ve got all this set up, you should find that when you commit to the repository, Cruise Control will detect this, update your working copy to the latest version, and then run the build script. If you browse to http://servername:8080 you should be able to see the results!

Hopefully that should be enough pointers to get you up and running without too much trouble…

Building applications November 1, 2007

Posted by Phill in General J2EE, Other Stuff.
Tags: , , , ,
comments closed

I came across this email exchange today, courtesy of today’s post at Jeff Atwood’s blog.

Unfortunately the scenario was all-too-familiar for me: in my first job as a developer, I was working for a small company. This meant that we were very busy, and little things like documentation were often missed (of course, this is something which bigger companies have been guilty of as well…) My development workstation became “The development machine”. This meant that when we needed to deploy an application, someone would come to me and say “Phill, we need a new EAR file for application x” (it wasn’t actually called ‘application x’, but actually that would have been kind of cool). I would then go into my IDE, open up the project, and run the build process.

The problem came when I needed to get someone else up to speed on the project… trying to get someone else’s IDE to be exactly the same as yours is a total nightmare. The dependencies were all over the place, it took hours to get it all up and running.