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.
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.
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.
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 } }
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
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.
registerCommand()
must be called once for each command line option. It is important to remember
that OpenTools in categories other than "Core" are typically loaded after the
command line has been parsed; any commands they register will arrive too late
to be recognized by the command line handler.
Each command registration requires two parameters:
Command
interface
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:
jbuilder -exampleEach option on the command line results in a call to the associated
Command
instance's
invokeCommand()
method.
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".
jbuilder -example one two three -example2 fourAdditional 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.
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.
Command
instances
Command
instance
One of JBuilder's own core OpenTools registers a default command which, unless overridden while parsing and invoking commands from the command line, continues to load the remainder of the IDE as follows:
Brows
er
instance
Scanning manifest from X:\jbuilder30\jdk.2\lib\jpda.jar Scanning manifest from X:\jbuilder30\lib\AwtMotifPatch.jar Scanning manifest from X:\jbuilder30\lib\beandt.jar Scanning manifest from X:\jbuilder30\lib\DBCSpatch.jar Scanning manifest from X:\jbuilder30\lib\dx.jar Scanning manifest from X:\jbuilder30\lib\jbcl.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 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.
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?
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.