Introduction to Trek Class LibraryThe Trek class library models Java code as a hierarchy of objects. A trek is a journey thru a list of classfiles and the objects in them. Each classfile contains fields and methods. A method in turn contains local variables and statements, and finally a statement contans instructions. The list of classfiles is established by initTrek. There are three types of applications you can write:
The source code for the JTrek applications included with JTrek are in the src directory of the JTrek kit. Summary of Trek API
Coding a simple Trek applicationYou would usually:
The method that does the trek should be coded as follows.
Example application that does an automatic scanThe following application would display the declaration of each class in the program identified via argv. import dec.trek.*; class mytrek extends Trek { public static void main(argv[]) { try { mytrek trek = new mytrek(); trek.getCmdLine(argv); trek.doTrek(); } catch (Exception e) { System.out.println(trek.toErrorMessage(e)); System.exit(1); } } // Called by doTrek as its scan reaches each classfile. public atStartOf(ClassFile cf) { System.out.println(cf.toString()); } } Example application that does a manual scanThis is the same application except that it does a manual scan. import dec.trek.*; class mytrek extends Trek { public static void main(argv[]) { try { mytrek trek = new mytrek(); trek.getCmdLine(argv); initTrek(); for (ClassFile cf=firstClassFile(); cf!=null; cf=cf.next()) { System.out.println(cf.toString()); } endTrek(); } catch (Exception e) { System.out.println(trek.toErrorMessage(e)); } } } Running a Trek applicationThe most simple case requires a command of the form: java mytrek class, where class is the fully qualified name of a class you want to scan. However for this command to actually work, your environment needs to be setup correctly:
If these things had not been setup, you would have to supply additional information on the command line to run this program:
If a program and its class libraries are large enough, it is possible for Java to run out of memory when it is executing a Trek application. If this occurs, an OutOfMemoryException will occur. To fix this, you need to increase the amount of heap memory available to the Java run-time. With java.exe for example, you do this by specifying the mxvalue switch. Creating and running an instrumented programThis section is an introduction to the Call class. Use of the Call class does not require any knowledge of the Java Virtual Machine or its classfile format. The Trek class library also provides the Code class, which can be used to insert and delete specific instructions in a program. Example application that instruments a programThe following application would instrument classes to display the name of each method that is called during a run of the instrumented program. import dec.trek.*; class mytrek extends Trek { public static void main(argv[]) { try { mytrek trek = new mytrek(); trek.getCmdLine(argv); trek.doTrek(); } catch (Exception e) { System.out.println(trek.toErrorMessage(e)); } } // Called by doTrek as its scan reaches each method. public atStartOf(Method meth) { Call call = Call.addBefore("Example.display", meth); call.passString(meth.toName()); call.done(); } } You would also need to create the class that contains then method(s) called by the inserted code: class Example{ public static void display(String name) { System.out.println(name); } } Using this JTrek applicationThe following commands would instrument MyProg.class and run the instrumented version -- assuming the classes of mytrek, Example, MyProg, and the Trek library were in the default classpath. java mytrek MyProg java MyProg Managing instrumented classfilesjava mytrek MyProg will overwrite the MyProg.class it scans. Thus you will need to rectify this before you can do your next un-instrumented run. Similarly if you instrument class libraries used by MyProg, by specifying java mytrek MyProg -sc user or a broader scope, JTrek will create instrumented copies of them under your current directory. Thus if your normal classpath has "." near its beginning, you will need to delete these files before you can do your next un-instrumented run. One way to avoid these issues is to create your instrumented classfiles in a separate directory tree. To do this:
If you were to do java mytrek MyProg twice, the instrumented MyProg.class would be the input file the second time. Thus you would end up with a MyProg.class that contained 2 calls to Example.display in each of its methods. To help you avoid doing this by accident, JTrek:
Error handling and debuggingIf you call a method in the Trek class library and it throws an error because it directly failed, the Trek class library will not catch the error. You of course can catch the error in your application, as described above. Most methods can throw errors as a result of programmer error, such as passing a null for a required argument. In general, method descriptions only document those errors that the program might want to "handle" at runtime. If a method in the Trek class library throws an error about a single object while processing a region of the program hierarchy, the Trek class library will catch the error, log it, and continue processing. The Trek objects log stream property controls where errors are logged to. Initially it is set to current-directory/trek.log. To set it to a different value, call setLogStream. After endTrek() completes processing of a trek, it checks if any errors have been logged. If so, it throws an "Errors logged" message that your application can catch, as described above. If you need to know what code threw an error or you wish to report a bug in the Trek class library, rerun the application with the debug switch set. This will cause a stack trace to be included in the output describing the thrown error. An instrumented classfile retains whatever debugger hooks the compiler put into it. In other words, you can run a debugger on an instrumented program. Thus you can set a breakpoint in a method called by code that you inserted. For example, you could use the watch application to insert a number of conditional watchpoints in your program, and then set a breakpoint at the method (ie. WatchLog.printLine) that is accessed when a watchpoint is actually hit. Advanced topicsCoding a GUI Trek applicationA GUI Trek application is typically organized as follows. You:
If you want to layer an application on simple Trek applications, you can set this up by expanding step 1 to be: SimpleApp1 trek = new SimpleApp1(); SimpleApp2 subtrek = new SimpleApp2(); subtrek.joinTrek(trek); If your application instruments programs and your user can insert and remove changes, you can code this by calling saveTrek and then cleanTrek each time you need to write the changes to disk. If you want to maintain a status line during a trek, you should:
If you want to save information about program objects between runs of your application, you can use toObjectId and getObject for this. Instrumentation via redirectionSometimes you want to understand how a program uses a class rather than insert code in the program itself. Whether you instrument the used class via JTrek or manually modify it, you can make your program use the instrumented class simply by placing its location earlier in the classpath than the real class. Similarly you can make a class in your program inherit different methods by placing an instrumented version of its superclass earlier in the classpath than the real superclass. To facilitate doing the same kind of thing on a per-method basis, the Trek class library provides methodref.redirect. By scanning thru the constant pools of your program and using redirect, you can make each call to a method use your copy of the method instead of the real method. Using the Trek class library from multiple threadsAny method in the Trek class library can be simultaneously called from another thread if the calls are applied to objects from different treks. After an initTrek has completed, multiple threads can freely access objects in its trek. But if a thread wants to modify objects in this trek, it must synchronize these operations with any other threads that access or modify objects in this trek. The methods that can modify objects in a trek are Trek.cleanTrek, Trek.endTrek, and Call.done, Code.done, and Instruction.delete, Statement.delete, and Statement.undoChange.
|