Offline post-compilation

This document explains the detail of the offline post-compilation feature provided by beSee. This mechanism allows to prepare the class files and jars you are using, instrumenting them thru some command lines calls, and use them or deploy them as usual, without using the beSee JVM wide hook architecture.

The offline mode also called compiler is independant from the bytecode kit (thus AOP framework) used to instrument classes.

To understand the concepts discussed here, you should read more about class preprocessor components.

  1. Supported environments
  2. Usage
  3. Samples

Supported environments

beSee offline compiler has been validated with the following environments:

  • java 1.3
  • java 1.4
There is no differences in using beSee in those environements.

beSee compiler makes use of Ant libraries to manipulate files and providing complete rollback feature in case an error occurs during the offline transformation of a class file.

Usage

beSee compiler is a regular java main class.

The following command is invoke to compile your compiled class / jars with the class preprocessor implementation given as argument:

    java -cp {classpath} com.gnilux.besee.compiler.BeseeC [-verbose] [-haltOnError] {ClassPreProcessorImpl} {target 1} .. {target n}
with the following requirements:
  • {classpath} must contain beSee jar (of course)
  • {classpath} must contain the jar for the bytecode kit needed by the class preprocessor (bcel.jar or javassist.jar or ...)
  • {classpath} must contain the needed jar (and/or classes) of the class preprocessor implementation
  • {ClassPreProcessorImpl} is mandatory and corresponds to the full qualified class name of the class preprocessor implementation
  • {target i} can be present any number of time and points to the zip, jar, classes (exploded jar) to be processed
  • use -verbose to have verbose output on stdout
  • use -haltOnError if you want the compilation to stop as soon as an error is detected

    In such a case, all changes made to given target(s) will be rollbacked.

    If -haltOnError is not specified , the compilation will rollback changes on the target for which the error occured and will go on with other targets. A summary will be printed on stdout at the end of all compilations.
Note that not all class preprocessor are compatible with offline mode. It depends on its implementation. During offline mode, the preProcess(className, byteCode, callerClassLoader) is called with null as callerClassLoader .

Samples

The following runs a compilation on a single jar test.jar and modify all classes (except interface) in order they implement an empty marker interface. You can reproduce this sample by calling the ant target demo.compiler .

Both the MarkerInterface and the AddInterfacePreProcessor compiled class will need to be in the classpath during compilation

package demo;

/**
 * Marker interface used to test Besee compiler
 */
public interface MarkerInterface { }
The following preprocessor instrument classes by adding them the MarkerInterface thru BCEL bytecode manipulation

package demo.preprocessor;

public class AddInterfacePreProcessor implements ClassPreProcessor {

    //... (refer to ClassPreProcessor specification)

    public byte[] preProcess(String klass, byte abyte[], ClassLoader caller) {
        try {
            // build the ClassGen
            ClassParser parser = new ClassParser(new ByteArrayInputStream(abyte), "<generated_"+klass+">");
            ClassGen cg = new ClassGen(parser.parse());

            // instrument
            if ( ! cg.isInterface() && ! Arrays.asList(cg.getInterfaceNames()).contains("demo.MarkerInterface") )
                cg.addInterface("demo.MarkerInterface");

            return cg.getJavaClass().getBytes();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
}
The following command instruments the test.jar file by adding the demo.MarkerInterface to all classes (except interfaces). It also updates the manifest.mf entry to keep track of the operation.
// assuming demo.MarkerInterface and demo.AddInterfacePreProcessor are compiled in ./classes/

java -cp besee-2-version.jar;classes;bcel.jar;ant.jar -verbose -haltOnError demo.AddInterfacePreProcessor path/to/test.jar

    [backup] Copying 1 file to C:\cvs_02\besee_sf\besee2\beseec\1
    [backup] Copying C:\cvs_02\besee_sf\besee2\build\test.jar to C:\cvs_02\besee_sf\besee2\beseec\1\test.jar
    [compilejar] C:\cvs_02\besee_sf\besee2\build\test.jar
    ...
    [compilejar] compile test.jar:org/apache/bcel/verifier/Verifier.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierAppFrame$1.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierAppFrame$2.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierAppFrame$3.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierAppFrame$4.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierAppFrame$5.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierAppFrame$6.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierAppFrame.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierFactory.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierFactoryListModel.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifierFactoryObserver.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifyDialog$1.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifyDialog$IvjEventHandler.class
    [compilejar] compile test.jar:org/apache/bcel/verifier/VerifyDialog.class
    [backup] removing backup
    [delete] Deleting 1 files from C:\cvs_02\besee_sf\besee2\beseec
    [delete] Deleted 1 directories from C:\cvs_02\besee_sf\besee2\beseec
    ( 2 s )
    SUCCESS: build\test.jar
The meta-inf/Manifest.mf of test.jar is updated this way for reference:
Manifest-Version: 1.0
Created-By: Apache Jakarta Maven
X-BeseeC-preprocessor: com.gnilux.besee.hook.impl.AddInterfacePreProcessor
X-BeseeC-created: 2003-07-09 15:58:23
X-BeseeC-comment: BeseeC - beSee compiler, www.gnilux.com
The VerifyDialog.class has been modified and now implements the demo.MarkerInterface. The decompiled class looks like:
// Decompiled by DJ v3.0.0.63 Copyright 2002 Atanas Neshkov  Date: 09/07/2003 16:03:01
// Home Page : http://members.fortunecity.com/neshkov/dj.html  - Check often for new version!
// Decompiler options: packimports(3)
// Source File Name:   VerifyDialog.java

package org.apache.bcel.verifier;

import demo.MarkerInterface;
..

// Referenced classes of package org.apache.bcel.verifier:
//            VerifierFactory, Verifier, VerificationResult

public class VerifyDialog extends JDialog
    implements MarkerInterface
{
..
}