Introduction

JJAR is an acronym for Jakarta JAR Archive Repository, an attempt at making a CPAN-like service/infrastructure for the Java development community.

Note :Until JJAR is officially in production, no guarantees will be made as to the correctness of the delivered jars. Best efforts will be made, but at any time, what you get might not be what you want.

Currently, JJAR is an experimental work in progress. It does work as advertised, and every effort is being made to ensure that it works at any point in time. However, as we are learning about what works and what doesn't, change will happen. Further this is currently not an official Apache Commons project, but a well-organized sandbox project. Therefore, production dependencies are discouraged.

Repeat : JJAR is neither an official Jakarta project, nor an official Apache Commons project. This document may have been found via a http://jakarta.apache.org/jjar/ link - it is there for information purposes for the repository.

Ok. Now that that's over, simply put, JJAR consists of two parts :

  • A distributed repository consisting of jars from various projects (which we call packages) as well as version and dependency information about those packages. This logical repository consists of a central main repository, and any number of sub-repositories, each responsible for a given project (or projects.)
  • A toolset to allow the navigation and fetching from this repository, as well as direct access to repository information, such as project dependencies.

Together, these two parts [hopefully] make up a complete system for package management and delivery for building Java applications.

The Repository

As currently defined, a repository physically consists of a directory containing a repository descriptor, an XML file containing repository information, and a set of jars described by that descriptor.

There is no strict requirement as to how a repository is implemented. The expected common implementation will be via http through a regular web server (no server-side programmatic support will be required.) However, in the case of local or enterprise use, it is expected that local file access will be enough. The technical limitation will be that there is a protocol handler for the access method of choice.

The central repository will be located on http://jakarta.apache.org/jjar/. The central repository will contain information on any project that does not want to host it's own repository. For any project that does host it's own repository (a remote repository), the central repository will simply contain information about the remote repository. The JJAR toolkit will use this information to tie the central and remote repositories together in a seamless manner.

The repository is distributed for several reasons :

  • This reduces the maintenance load on the Jakarta volunteers that manage JJAR.
  • It allows easy inclusion of non-Jakarta projects.
  • It allows the developers of projects to define their dependencies and use JJAR to assist in their own build processes if using Ant. In other words, JJAR can be used to get the jars that satisfy the dependencies for the building of their project, thus removing the requirement of putting support jars in CVS, or worse, making users go on a treasure hunt gathering the required jars.

The Toolset

The toolset is designed for general command-line use, integration with Java applications, and direct integration with Ant the fab Java-based build tool (rapidly becoming the Perl of Java...).

Commandline Tool

For command line use, a small Java program has been included. It is included in the jjar.jar distribution jar. To use it, it is invoked as :

     $ java -jar jjar.jar command [parameters]
  
Where command is the main action to take, and parameters are the action-specific parameters of the command. The current set is listed below :


list [-p packagename] : List one or all packages in repository
Example : java -jar jjar.jar list

verify [-j jarname] : Verify jars in the classpath, or individually
Example : java -jar jjar.jar verify -j foo.jar

fetch -p package [-nd | -od] [-vi] [-d directory] [-v version] [-j outputjarname] : Fetch jars from the repository
Notes: -nd = no depeondences. -od = only dependencies. -vi = 'verify ignore' - will check to find each package/dependency and not fetch if found. Without -j, will go to 'default name'. Without -v, will get 'default' version. -d specifies local directory to hold the jars (the local repository).
Example : java -jar jjar.jar verify -j foo.jar

Please note that this documentation may be incomplete.

Jakarta Ant Support

JJAR also offers direct support for the fabulous Java-based build tool Ant. Please see the Ant site for more information. The following assumes that you understand the basics of Ant, and that you have it installed on your computer.

Ant support in JJAR is intended to simplify building projects by providing a facility to fetch the packages that a project depends on, as well as the dependencies for that package. The driving idea here is that a project will use JJAR to get any packages it depends on, and therefore removes the requirment of providing those jars to the users or developers of the package.

To do this, JJAR includes the JJARTask class that is an Ant task, and can be used directly in Ant. It is use like this. The following bit of a build.xml ant 'script' comes from the /examples/ant-task/ example in the JJAR distribution :


 <!-- declare our 'jjar' ant task. Assumes jjar.jar in  -->
 <!-- local directory                                   -->

 <taskdef name="jjar" classname="org.apache.commons.jjar.JJARTask">
    <classpath>
      <pathelement location="jjar.jar"/>
    </classpath>
  </taskdef>

  <!-- task to get jars for the jakarta-velocity package -->
  <!-- version 1.2-dev, and places them in the           -->
  <!-- ${rep.local} repository                           -->

  <target name="fetchjars">

     <jjar package="jakarta-velocity" 
           version="1.2-dev"
           localrepository="${rep.local}">
     </jjar>

  </target>
So what we did here was define a task <jjar> to Ant, and then invoked the jjar task to fetch the jar and dependency jars for the jakarta-velocity package, version 1.2-dev.

A more interesting example is how to then let jjar get some dependencies and also add them to the classpath. Again, from the /examples/ant-task/build.xml example :


<!-- assume jjar task defined...           -->

<target name="test-classpath">

    <!-- use JJAR to fetch the Velocity package and -->
    <!-- dependencies, placing in the repository    -->

    <jjar package="jakarta-velocity" 
          version="1.2-dev"  
          pathrefid="jjarclasspath" 
          localrepository="${rep.local}">
    </jjar>

    <!-- lets see if that worked -->
    <property name="jjarpath" refid="jjarclasspath"/>
    <echo message="jjarclasspath:  ${jjarpath}"/>

    <!-- now compile the test file, using the jjar classpath -->
     <javac  srcdir="${src.dir}"
             destdir="." >
            <classpath refid="jjarclasspath"/> 
     </javac>
	
  </target>

Here, we use JJAR to fetch Velocity, but then let JJAR add those jars to a path called 'jjarclasspath', which we then include in the <javac> task, using the jars to build the code.

The important thing about that last example is that as a user of Velocity, you no longer care what the Velocity developers add as dependencies to their project - as they add dependencies, they will update the repository, and the jars will automatically be downloaded, and automatically added to the classpath for building.

Use Cases

There are quite a few use-cases that have been identified, and by listing them here, it is hoped that you get a flavor of what this is about, if the flowery prose above didn't get the idea across.

In many of the examples below, the command line JJAR tool will be demonstrated. To use it, you must build the jjar.jar file. Please see the section on 'Building JJAR'.

Listing All Packages In The Repository

This is the simplest use of the toolset - you simply want to see whats there. Currently, you can do this with the command line tool :

   java -jar jjar.jar list
And you will get a list of all packages and dependencies dumped out, something like :

JJAR : Jakarta Jar Archive Respository v0.1
===================================
       
Repository contains 9 packages : 

  veltag
    desc     : Velocity JSP taglibrary
    default  : 0.01-dev
    versions : 
      0.01-dev deps : jakarta-servletapi:4.0, jakarta-commons-collections:0.0-1, jakarta-velocity:1.2-dev, 
--

 jakarta-velocity
    desc     : Jakarta Velocity template engine
    default  : 1.0-1
    versions : 
      1.0-1 deps : 
      1.1 deps : jakarta-commons-collections:0.0-1, 
      1.2-dev deps : jakarta-commons-collections:0.0-1, 
--

 jaxp-parser
    desc     : Java API for XML Processing
    default  : 1.0
    versions : 
      1.0 deps : 
--

Listing A Single Package

In the (usual) case where you weren't interested in the entire repository, you can simply see the information and dependencies about a specific package :

   java -jar jjar.jar list -p package
Where package is the package you wish to query, of course. You might see :

[gmj@192 jjar]$ java -jar jjar.jar list -p jakarta-velocity

JJAR : Jakarta Jar Archive Respository v0.1
===================================
       
 jakarta-velocity
    desc     : Jakarta Velocity template engine
    default  : 1.0-1
    versions : 
      1.0-1 deps : 
      1.1 deps : jakarta-commons-collections:0.0-1, 
      1.2-dev deps : jakarta-commons-collections:0.0-1, 
--

This output tells us a few things. First, that the repository knows about 3 versions of Velocity, 1.0-1, 1.1 and 1.2-dev. Next, it lists the dependencies of each of the versions, both the package as well as the version. Finally, it tells us the default version of the package, in the event that we had no preference.

Verify a Jar (show package and version)

Suppose you have a jar, and wish to figure out what JJAR package name and version it is. JJAR's toolset can do that :

     java -jar jjar.jar verify -j jarname
where jarname is the JAR file you wish to query. This can be useful to check a set of jars to make sure that they satisfy all dependencies.

Fetching a Package

Use JJAR to fetch a package and it's dependencies :

    java -jar jjar.jar fetch -p jakarta-velocity -v 1.1
The jars will be placed in the current directory.

Project Self-Dependency with Ant

An interesting use-case is demonstrated by the Veltag JSP taglib contribution in the Jakarta Velocity project. (Look in the /contrib/temporary/veltag directory.)

  • This project maintains its own repository descriptor, and keeps it in the project's CVS.
  • This project has an entry in the central repository which points back to the project's CVS, so the JJAR toolset will first go to the central repository, and then get the Veltag information from the Veltag CVS.
  • The project's build script has the following :
      
      <!-- target to bootstrap by fetching jjar from central repository -->
      <target name="getjjar" depends="jjarcheck"  unless="jjar.present">
         <get src="http://207.138.188.222/jjar/jjar.jar" dest="${bin}/${jjar.jar}"/>
      </target>
    
      <!-- normal compile target uses JJAR to fetch dependencies -->
      <target name="compile" depends="static" description="Compile">
    
        <taskdef name="jjar" classname="org.apache.commons.jjar.JJARTask">
           <classpath>
              <pathelement location="${bin}/${jjar.jar}"/>
           </classpath>
        </taskdef>
    
        <jjar package="veltag" 
              onlydependencies="true"  
              verifyignore="true" 
              localrepository="${local.repository}"
              pathrefid="jjarclasspath"  >
        </jjar>
      
        <javac  srcdir="${source.home}/java"
                destdir="${build.home}/classes"
                debug="${compile.debug}"
                deprecation="${compile.deprecation}"
                optimize="${compile.optimize}">
            <classpath refid="jjarclasspath"/>
        </javac>
    
      </target>
    
      
    which causes the plain-vanilla build to use JJAR to find it's own dependencies, fetch the dependencies, and place them in the classpath to use in the build.

The end result is that the Veltag developers, who dictate their project dependencies anyway, use the JJAR repository mechanism as the single point of maintenance, which then provides inclusion of the Veltag project in the JJAR repository system, as well as a maintenance free build.xml file. As they add external dependencies to the project, they automatically get included in the build.

To the user, after they get a snapshot of CVS or a distribution copy, all they have to do is :

  $ ant getjjar
  $ ant jar
The first command is a 'bootstrap' which does a simple ant 'get' to get a copy of JJAR from the repository. The second builds the jar, using JJAR to figure out the dependencies, fetch needed jars, and add those to the classpath.

Then, as the project evolves and the developers add new dependencies (or the developers of the existing dependencies change things) then anyone building this project is immune to those changes, as a simple

  $cvs update
  $ant jar
will take care of all.

Note, there are still quite a few details to be worked out with Ant support...