Thursday, February 24, 2005

It's the simple things

A phenomena that I've seen occur when trying to find information on the internet, especially regarding Open Source technologies, is that it's very hard to find a concise set of instructions to bootstrap yourself when learning. Simple things you need to know in order to get started are assumed, omitted, or forgotten.

So, today, I've been working on picking Java up where I left off 2 years ago. Back then, I'd taken a class or two, and learned enough to realize what I was talking about. I didn't understand what I was doing entirely, but I accomplished what I needed to in order to get the grade. Today I'm working on understanding.

Specifically, I wanted to work on using Ant to build a java app that I could use for a custom JSP Tag. I decided that I'd first try to compile a program with multiple classes within a package. Now, stop.

This task should be simple enough. In fact it is simple if you know what you're doing. I didn't.

Problem 1. I kept getting compile errors because I didn't have the package defined correctly. How do you use packages when building a java app? The solution was to do the following:

  1. Put the main class' java file in a directory.
  2. Make a directory with the name of the package the main class uses and put it in the same directory as the main class java file.
  3. At the top of the main class file write:
    import packageName.*;
  4. In each of the .java files for the package you're using, write this at the top of the page:
    package packageName;
    import packageName.*;

  5. Put all of the java files for the package in the directory with the package name
  6. Then you can compile the thing with a command prompt and javac:
    prompt$ javac MainClass.java
  7. If it doesn't work, don't blame me ;-)
OK, that worked. But I wanted to use Ant. Fortunately, ant is extremely easy to use. Just read the docs and get it installed correctly.

Problem 2. How do I set up ant to work for my application?

Fortunately the docs are reasonably good for this app. I had good luck simply customizing the existing example build file. When you have that set up, just make sure to customize the project names and directories you want, and put it in a directory with the same directory tha tholds all of your source code (I used a dir called 'src', as the build file uses). This XML build file must be named 'build.xml'. Then, you can take a prompt, cd to that directory where the build.xml file is, and type 'ant' at the prompt. It will do the building for you. Cool!

Problem 3. How do I get the jar file that ant builds to run as an executable?

Even though this doesn't really have to work in order to build a tag for JSP, I wanted to do it anyway, to see if I could do it. Ant is cool because it automates lots of commands that you'd use when building an app, including the generation of a .jar file. Handy! The only thing is, the jar file that it generates doesn't become executable by default. The solution involves the following:

  1. Set up the MANIFEST.MF file in the META-INF dir of the jar so that it knows which class is the main one to call when executing. This means putting a 'Main-Class:' declaration in that file.
  2. Customizing the build.xml file that ant uses
After noodling around, I adjusted the manifest just fine. and that worked. Then I wanted to use ant to make the MANIFEST.MF file for me. To do that put in a couple lines as a child node to the tag:

<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}/lib"/>



<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/lib/FactoryPattern.jar" basedir="${build}">
<!-- set up the MANIFEST -->
<manifest>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Main-Class" value="${app}"/>
</manifest>
</jar>
</target>

Here's some handy tips:
  • For what it's worth, a jar file is just a zip file with a different extension
  • jar works much like tar. To create a jar file type:
    jar cf [input directory and input files] [output file].jar
  • If you want to add a mainfest file, you can do the following:
    jar cmf [input directory and input files] [path/to/MANIFEST.MF] [output file].jar
  • To extract a jar file:
    jar xvf [jarfile].jar
  • To run an executable jar file from the command line:
    java -jar [jarfile].jar
I know these are simple things, and I realize that this is the same kind of non-comprehensive set of information that I was complaining about, but, hopefully this will be helpful enough to get'cha started.

[UPDATE]
I had trouble getting the classpath set up correctly at first, but ant handles it quite elegantly. Basically, you set up a path variable in the build.xml file, and then refer to it in the tag when building.


<path id="base.path">
<fileset dir="${tomcat.home}/common/lib/">
<include name="**/*.jar">
</fileset>
</path>

<!-- THEN THE COMPILE TARGET, AND JAVAC, LOOK LIKE THIS -->
<target name="compile" depends="init" description="compile the source " >
<javac srcdir="${src}" destdir="${build}" >
<classpath refid="base.path"/>
</javac>
</target>
The benefit of keeping the classpath info in the build.xml file is that it doen't need to be set in the shell when you're dealing with custom classes and third party stuff

No comments: