Up, up, and away: deploying your projects

First version: 11-Feb-2010 by Rick Manning

Table of Contents

Introduction

De·ploy·ment (n):
  1. How a software project is packaged and delivered to those who will use it.
  2. The easiest way, if done wrong, to annoy your graders.

Sometimes comp314 students (especially those with little experience beyond classroom projects) have difficulty turning in their projects in a way that makes them easy to use by the graders. This tutorial is meant to help prevent that. We'll cover the basics of Java project structure, Java classpaths, Eclipse classpath files, libraries, and READMEs. Use this knowledge and you'll make your graders very happy!

Project layout

Good deployment starts with good directory structure. Directories exist so that you can divide your files into smaller groups and find things more easily---a good directory layout will make it easy for you and those who use your project to find the files they're looking for.

Many Java projects use the following conventional layout:

+-[project root]
  +-bin/      (compiled .class files, not kept under version control)
  +-doc/      (specification, javadocs, etc.)
  +-lib/      (any external libraries [see below])
  +-src/      (project source code, subdivided by package)
  +-README
  +-[...]

In a slightly broader scope, here's the way we recommend arranging your Subversion folder:

+-projects/
  +-p1/
    +-g01/
      +-branches/
      +-tags/
        +-spec/         (created by tagging the trunk at spec deadline)
        +-beta/         (created by tagging the trunk at beta deadline)
        +-final/        (created by tagging the trunk  at final deadline)
      +-trunk/          (your group's project root - all work is done here)
        +-doc/        
        +-lib/
        +-[etc.]

Notice that the project root is the trunk directory. This allows your group to submit your spec, beta, and final milestones very easily: in Eclipse, just right-click your project and select "Branch/Tag..." from the Team menu, then specify the appropriate folder (e.g. /tags/spec), enter a commit message, and hit "Finish":

Tagging a project for the spec deadline in Eclipse.

Remember that these directory layouts are merely suggestions---the only strict requirements here are that you have a tags folder with your submissions and that your project root is reasonably navigable.

Java classpaths

In order to execute a Java program, the Java Runtime Environment (JRE) needs to access compiled (.class) versions of any and all classes referenced by the program. Many of these will be provided by the program itself; that is, your compiled project will contain a .class file for each of the classes you define. These generally reside in the bin folder.

As an example, consider a simple one-class Java program called "Blarg." This program has one class, Blarg, whose main() method simply prints out a message. Suppose our project root contains a class folder and a source folder, containing Blarg.class and Blarg.java, respectively:

$ ls
bin	src

From here, an attempt to run Blarg with a plain command will fail:

$ java Blarg
Exception in thread "main" java.lang.NoClassDefFoundError: Blarg
Caused by: java.lang.ClassNotFoundException: Blarg
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:315)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:330)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:250)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:398)

This is because, by default, the Java interpreter looks only in the current directory (i.e. the directory in which the java command was executed) for the class files it needs. Had we cd'ed into the bin folder and executed that same command from there, it would have succeeded.

However, we generally do not want to require users to be in the bin folder to run our program; it is more convenient to run it from the project root directory. Running it from the project root also allows the program easier access to files not in the bin folder, such as test input files (which could be, for example, in a resources subdirectory of the project root).

So, how do we invoke the Java interpreter from one directory while giving it access to class files in another directory? By passing it a so-called classpath (AKA build path) with the -classpath option. Since our class files are in the bin directory, the following command is what we need:

$ java -classpath bin Blarg
blarg!

At this point you may wonder how the Java interpreter can access classes like java.util.LinkedList and java.lang.String, even though your project does not include class files for them. Such classes are part of the Java Platform and as such, the interpreter automatically knows where to find them on your machine.

Packages

The above example used a class with no package---this is rare in actual Java programs and also bad Java style. To provide a more realistic example, suppose we have a Java project called Flarg, in which there is a top-level package flarg that contains all subpackages for the application. There are two subpackages: app, which contains the main application class, and util, which contains two support classes. Since Java is very strict about the relationship between classes and their locations on the filesystem, this package structure means we must have the following file structure (supposing that all our compiled class files are stored in bin):

+-bin/
  +-flarg/
    +-app/
      +-FlargMain.class
    +-util/
      +-Flarginator.class
      +-DeFlarginator.class

(The Java compiler automatically puts your class files into the correct hierarchy as long as your source files are organized correctly.)

Since we have packages, the java command to execute our program (which again we run from the project root) will look a little different:

$ java -classpath bin flarg.app.FlargMain
flarg!

Note that we specified the package path to the main class (using periods), not the file path (which would use slashes).

For comp314, your READMEs should include a command like the above which runs the main method of your application (see Writing a README).

Using external libraries

An external library is any chunk of code your project uses that is not strictly part of your project nor part of the Java Platform itself. For example, if my Flarg project makes use of the JDOM XML parser, all the JDOM code (which is probably wrapped into a single .jar file) would be considered an external library.

The term dependency crops up a lot when discussing libraries. A dependency is anything your project requires (depends on) to run. In the above example, we could list the JDOM library as one of Flarg's dependencies. Technically speaking, all Java programs depend on the JRE and the standard classes it uses. However, external dependencies, which are not part of the project or the Java Platform (like the JDOM .jar file) are generally the trickiest to use correctly.

Let's return to my Flarg project. Suppose I want to use FlargChecker, a collection of classes that somebody else wrote, in my project. Typically, I would download the library (in this case the code is distributed as FlargChecker.jar) and place it in my projects directory (in my case, under the lib folder):

+-[project root]
  +-bin/
    +-[class files]
  +-lib/
    +-FlargChecker.jar
  +-src/
    +-[source files]
  +-[...]

I can now make reference to the classes in FlargChecker.jar in my own code, but my project will not compile if I don't tell javac where to find FlargChecker.jar. I do so by passing the classpath argument to javac:

$ javac -classpath lib/FlargChecker.jar -d bin [source files]

(The -d option tells javac where to place the generated class files.)

Now that our project is compiled, we can run it. However, we still have to tell the Java interpreter the location of our external library! The above step does not, for example, copy all the .class files from the dependencies into our project (otherwise projects with many dependencies would become vast, and any projects that used those projects would become even more vast, and so on). Since we now have to tell the interpreter where to find our class files as well as where to find the FlargChecker class files, we have to specify two paths on the classpath. We use a colon to separate paths:

$ java -classpath bin:lib/FlargChecker.jar flarg.app.FlargMain
flarg! (this message verified by FlargChecker)

And there you have it! You can now compile and run programs with external dependencies on the command line. Read on to discover how Eclipse manages most of this for you, and how you should configure Eclipse to do it right.

Classpaths and libraries in Eclipse

IDEs like Eclipse are wonderful tools. They let the programmer ignore some of the nitty-gritty details about classpaths and the command line and get straight to the programming. You can click a button and your program just runs. But this convenience comes at a cost: it's harder to learn those nitty-gritty details in the first place, so when you need them, you're forced to resort to Googling (or posting on IRC!). So let's see how Eclipse manages all this for you.

If you have a project open in Eclipse, that means you've already done two things: you've created a workspace, and you've created a project within that workspace. For these examples, our workspace is a folder called ECLIPSE_TEMP, and our projects are, as required by Eclipse, direct subfolders of that folder. In particular, we have an Eclipse project called Flarg, laid out as described above (with packages flarg.app and flarg.util, but without the lib folder at this point).

Eclipse keeps the most important settings about a particular Java project in two files: .classpath and .project. Both of these will be in the project root:

$ ls -a
.		.classpath	.settings	src
..		.project	bin

(You'll notice there is also a .settings directory. This contains other Eclipse settings, but I won't talk about them here.)

The .classpath file

Let's look at the .classpath file for this project:

$ cat .classpath 
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry kind="src" path="src"/>
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/
org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
	<classpathentry kind="output" path="bin"/>
</classpath>

What does this XML file tell Eclipse? Three things:

Suppose we again want to add the FlargChecker.jar library to our project so our own classes can use it. We can make a lib directory to the project and put the .jar file into it, but that's not enough to let our classes reference it. Recall that before, we had to tell javac where to find every library we wanted to use; likewise we have to tell Eclipse where to find each library. We can do this by modifying our project's class path (also known as the build path) from within Eclipse.

To add a library to an Eclipse project, right-click the project in Eclipse's "Package Explorer" panel, and select "Properties". Select the "Java Build Path" item on the left side, and go to the "Libraries" tab in the middle. Click the "Add JARs..." button. This will bring up your project directory and let you navigate to any JAR files in it that are not already on the build path. Select one, and it will appear in the list of JARs and class folders on the build path, like so:

The Flarg project with a properly configured FlargChecker library.

Modifying our project's build path has added another line to our .classpath file:

<classpathentry kind="lib" path="lib/FlargChecker.jar"/>

Congratulations! Our Eclipse project can now use that library. Important: If you use any libraries, be sure to commit them to the SVN repository. Also make sure your .classpath file is under version control, so that your partner's copy of Eclipse will know about the library as well.

The .project file

coming soon...

Writing a README

Including a good README with your project is one of the most helpful things you can do for your graders. A good README will probably touch on all the following topics:

AdvANTsed topics

coming soon...

Links

coming soon...