JBuilder uses a dynamic discovery mechanism to load itself rather than a hard coded startup process. There are actually only two class files at the heart of JBuilder: the PrimeTime class and the Command interface.
The PrimeTime class provides a variety of methods for loading OpenTools and interpreting a command line. The actual process of discovering OpenTools is entirely automatic and is described in detail in the next section.
The Command interface defines a self-describing command line option. Each implementation of the interface provides a one-line description of the option, brief online help, and the actual command processor that handles requests.
There is no single class or interface that embodies the concept of an OpenTool. Each OpenTool can inherit from any class, though it must be public and it must define a single method used to initialize the tool. The OpenTool initialization method must have the following signature:
public static void initOpenTool(byte, byte)
This approach provides a very open ended foundation for extensibility with minimal additional complexity. An extension to JBuilder need only be added to the classpath and it will automatically be initialized at the appropriate time.
OpenTools are discovered by searching the current classpath for special manifest entries. An OpenTools entry in the JAR's manifest starts with the string "OpenTools-" and is followed by an OpenTools category. The value of the manifest entry must be a space delimited list of fully qualified class names, each of which must be a valid OpenTool.
The following manifest file describes a single OpenTool class in the "Core" category:
OpenTools-Core: com.borland.primetime.vfs.FileFilesystem
There is an alternative mechanism for finding OpenTools that is designed to be used only during development. This mechanism is described below under "Defining OpenTools During Development."
A valid OpenTool need only be a public class that implements a single static method matching the required signature:
public static void initOpenTool(byte, byte)
This method is invoked once when JBuilder is loading, giving the OpenTool a chance to do whatever initialization is appropriate. The two parameters passed to the initOpenTool method describe the version number of the OpenTools API implemented by JBuilder.
The two parameters passed to an OpenTool are the major and minor version numbers. The major version number is incremented when the OpenTools API changes in a way that breaks compatibility with existing OpenTools, and the minor version number is incremented when features are added to the OpenTools API.
Each OpenTool must check the major version number before performing any registration tasks. The following template illustrates the standard implementation technique for this requirement:
public class examples.opentools.Sample {
public static void initOpenTool(byte majorVersion,
byte minorVersion) {
// Make sure the OpenTools API is compatible
if (majorVersion != PrimeTime.CURRENT_MAJOR_VERSION)
return;
// Perform OpenTool initialization
}
}
The following is an example of a trivial OpenTool that does nothing but greet the user at load time:
public class examples.opentools.GreetUser {
public static void initOpenTool(byte majorVersion,
byte minorVersion) {
// Make sure the OpenTools API is compatible
if (majorVersion != PrimeTime.CURRENT_MAJOR_VERSION)
return;
// Perform OpenTool initialization
String userName = System.getProperties().getProperty(
"user.name");
System.out.println("Greetings, " + userName + ".");
}
}
OpenTools must be compiled and added to the classpath before starting JBuilder,
and the OpenTools discovery process needs to be able to find the class name at
startup. To accomplish this you'll need to create a manifest file that looks
something like this:
OpenTools-Core: examples.opentools.GreetUser
Note that manifest file must conform to the guidelines set forth by Sun. Entries are case sensitive, the manifest file cannot include blank lines, each line must end with a line terminator, and only the last entry found with a given name is used.
To initialize more than one OpenTool in a single category using a single manifest file you must use a space delimited list of class names. The manifest file format will allow a single entry to span more than one line, however each line continuation must begin with a space character and this character does not count as a space between entries. As a result, each new line with a class name should start with two spaces. The following example uses the text "<space>" to indicate the presence of a space character for clarity:
OpenTools-Core:<space>examples.opentools.OpenToolOne
<space><space>examples.opentools.OpenToolTwo
There are times when you may wish to replace existing functionality by suppressing an existing OpenTool and providing a replacement that serves the same purpose. Any entry in the OpenTools list that starts with a minus character is treated as a request to suppress the OpenTool of the specified class name:
OpenTools-Core:<space>-examples.opentools.OpenToolOne
The category associated with the suppression request is ignored. The presence of the above entry in any manifest file on the classpath would prevent the OpenTool "examples.opentools.OpenToolOne" from ever being initialized.
Each command registration requires two parameters:
Note that the option name must be supplied without a leading hyphen, as shown in the following example:
PrimeTime.registerCommand("example", new ExampleCommand());
The preceding statement would allow JBuilder to react to a command line that uses
a leading hyphen to indicate the presence of an option. The remainder of the option
name is case-sensitively matched to the appropriate command:
Each option on the command line results in a call to the associated Command instance's invokeCommand method.jbuilder -example
Commands that can accept one or more arguments should override takesCommandArguments and return true. These commands will be passed everything between their command line option and the following option as a parameter when invoked. In the following example the handler for "example" will receive the three command arguments "one", "two", and "three".
Additional methods defined by the Command interface require each command to return a brief one line self description from getComandDescription, and to print a more detailed description when printCommandHelp is called. The textual descriptions provided are available to the end user via the built-in "-help" command line option.jbuilder -example one two three -example2 four
After invoking all other command line handlers JBuilder will always invoke the default command line handler. This is the command most recently registered with a null option.
The OpenTools provided with JBuilder will automatically register a default command handler when the "Core" OpenTools are initialized that starts the full graphical IDE. Third-party OpenTools can take action during their invokeCommand method if the normal IDE load process needs to be circumvented. The following statement is sufficient to prevent the graphical IDE from loading:
PrimeTime.registerCommand(null, null);
| CLASSPATH entry | Override manifest filename |
| c:\classes\ | c:\classes.opentools |
| c:\classes.zip | c:\classes.zip.opentools |
If found, the "override" manifest is used and the actual manifest file is ignored.
The first eight lines above describe the discovery process, detailing exactly which files are being used to gather a complete list of OpenTools available. The next line reports how long the complete discovery process took.Scanning manifest from X:\jbuilder30\jdk1.2.2\lib\jpda.jar Scanning manifest from X:\jbuilder30\lib\AwtMotifPatch.jar Scanning manifest from X:\jbuilder30\lib\beandt3.1.jar Scanning manifest from X:\jbuilder30\lib\DBCSpatch.jar Scanning manifest from X:\jbuilder30\lib\dx3.1.jar Scanning manifest from X:\jbuilder30\lib\jbcl3.1.jar Scanning manifest from X:\jbuilder30\lib\jbuilder.jar Scanning manifest from X:\jbuilder30\lib\ext\PalmDeployer.jar OpenTools discovered (110ms) --- Initializing OpenTools-Core OpenTool com.borland.jbuilder.JBuilderToolkit (170+701ms) OpenTool com.borland.primetime.node.FolderNode (371+0ms) OpenTool com.borland.primetime.node.ImageFileNode (20+20ms) OpenTool com.borland.primetime.node.TextFileNode (0+0ms) OpenTool com.borland.jbuilder.node.PropertiesFileNode (20+10ms) OpenTool com.borland.jbuilder.node.ClassFileNode (10+0ms) OpenTool com.borland.jbuilder.node.CPPFileNode (10+0ms) OpenTool com.borland.jbuilder.node.HTMLFileNode (10+0ms) --- OpenTools-Core initialized (1493ms total)
The next nine lines describe the process of loading each defined Core OpenTool in turn. The paired times shown in parenthesis describe time to load the class and the time spent running the initOpenTool method. These times should typically be less than 100ms combined, performing absolutely minimal initialization during startup. Time-consuming initialization should be deferred until the first time the feature is actually used.
The last line summarizes the combined time spent loading and initializing every OpenTool in a particular category. This value is the measured elapsed time rather than a sum of the times reported for individual OpenTools.
Complex OpenTools may wish to provide hooks for other OpenTools to customize their behavior even further. The text editor in JBuilder is one such example, allowing OpenTools in the "Editor" to register keymaps and other specialized behavior.
Why create a new category instead of just registering everything in the "UI" category?
Inprise reserves the right to use any category name that does not start with a package-like domain prefix. Third parties should use a category name based on one of their domain registrations to avoid name collisions. For example: Amazon.com might choose to use "com.amazon.Book" as a category.
The static initializeOpenTools method can be used to initialize all OpenTools belonging to a specified category. The method will return once each tool registered in the category has been initialized.