More on OSA's New Tools Platform, ConsoleOne
Articles and Tips: article
Senior Research Engineer
01 Mar 1998
If you have read some of the earlier articles on OSA (Open Solutions Architecture) in this issue, you have learned that it is a brave new day at Novell. We are committed to making your applications easier to register, discover, install, configure, manage, and update across the network.
You've probably already heard that Novell was working on a new Java-based administration tool. You probably think that this new tool will replace the Wintel-based NetWare Administrator application. Well, as this article will explain, this assumption is both right and wrong.
The new Java-based administration tool to be released with NetWare 5 will be called ConsoleOne. Although, it will perform basic NDS administration in the NetWare 5 release, this version will not yet provide the same level of functionality as good old NetWare Administrator.
On the other hand, there are some notable benefits even with this early version of ConsoleOne. First, it will run on any platform which can run a Java virtual machine, including the NetWare server. Second, ConsoleOne can be extended to browse and interact with just about any namespace imaginable. You see, ConsoleOne is not just an NDS administration tool, it is really a namespace browser and tools receptacle. But, what do we mean by a namespace?
The term namespace as it would be used for ConsoleOne is any container which contains objects with names. Examples of a namespace could be a directory like NDS, a file system, or any database. So then, any entity on the network which contains things that are accessible by name could ultimately be browsed and managed by ConsoleOne (with a little work from you, of course).
Eventually, Novell may even deliver a version of ConsoleOne as an applet to allow administrators to manage their networks from any browser.
NetWare 5's version of ConsoleOne however, is a Java stand-alone application.
ConsoleOne Class Hierarchy
On the following pages, you will find a class hierarchy listing to give you a quick idea of the makeup of ConsoleOne.
class java.lang.Object interface com.novell.application.console.snapin.AskPerInstanceSnapin class java.awt.Component class java.awt.Container class com.sun.java.swing.JComponent class com.sun.java.swing.AbstractButton class com.sun.java.swing.JMenuItem class com.novell.application.console.snapin.DefaultMenuItem class com.sun.java.swing.JComboBox class com.novell.application.console.util.objectentryselector.TreeCombo class java.awt.Panel class com.novell.application.console.snapin.SimplePageSnapin class java.awt.Window class java.awt.Dialog class com.sun.java.swing.JDialog class com.novell.application.console.util.objectentryselector.ObjectEntrySelector class com.novell.utility.nmsgbox.NMsgBox interface com.novell.application.console.snapin.DisplayImageSnapin interface com.novell.application.console.snapin.DisplayNameSnapin class java.util.EventObject class com.novell.application.console.snapin.ShellEvent class com.novell.application.console.snapin.PageHostEvent class com.novell.application.console.snapin.SnapinEvent interface com.novell.application.console.snapin.ExtendChildrenSnapin class com.novell.application.console.snapin.MainShell interface com.novell.application.console.snapin.MenuSnapin interface com.novell.application.console.snapin.NameMapSnapin interface com.novell.application.console.snapin.NamespaceSnapin class com.novell.application.console.snapin.ObjectEntry interface com.novell.application.console.snapin.ObjectEntryEnumeration class com.novell.application.console.util.objectentryselector.ObjectEntryFilter class com.novell.application.console.snapin.ObjectType interface com.novell.application.console.snapin.PageHost interface com.novell.application.console.snapin.PageSnapin interface com.novell.application.console.snapin.PersistenceSnapin interface com.novell.application.console.snapin.ProxySnapin class java.util.ResourceBundle class java.util.ListResourceBundle class com.novell.utility.nmsgbox.Resources interface com.novell.application.console.snapin.ServiceSnapin interface com.novell.application.console.snapin.Shell class com.novell.application.console.snapin.ShellAdapter interface com.novell.application.console.snapin.ShellListener class com.novell.application.console.snapin.SimpleContextMenuSnapin class com.novell.application.console.snapin.SimpleStatusBarSnapin class com.novell.application.console.snapin.SimpleToolBarMenuSnapin interface com.novell.application.console.snapin.Snapin class com.novell.application.console.snapin.SnapinCollectionInfo class com.novell.application.console.snapin.SnapinItemInfo interface com.novell.application.console.snapin.SnapinListener interface com.novell.application.console.snapin.StatusBarSnapin class java.lang.Throwable class java.lang.Exception class com.novell.application.console.snapin.SnapinException class com.novell.application.console.snapin.NoParentException class com.novell.application.console.snapin.NotAContainerException class com.novell.application.console.snapin.ObjectNotFoundException class com.novell.application.console.snapin.SnapinVetoException interface com.novell.application.console.snapin.ToolBarSnapin interface com.novell.application.console.snapin.VetoableSnapinListener interface com.novell.application.console.snapin.ViewSnapin
The entries in the class hierarchy listing are in the form of fully qualified names. For example, in the entry, com.novell.application.console.snapin.NamespaceSnapin, the prefix com.novell.application.console.snapin specifies the location of the Java class package directory that contains the class NamespaceSnapin.
The dots (or ".") are name context delimiters. So, the DOS equivalent of the entry would be com\novell\application\console.snapin\NamespaceSnapin and this is what you would see if you looked inside of the JAR file.
The package statement that you write for each source file tells the build environment in which directory to put the classes compiled from the file. Usually, programmers put classes of like purpose together into the same directory or package. Often all of the packages relating to a given purpose are zipped up into the same JAR file which is then put into the ConsoleOne snap-ins directory so that ConsoleOne can accesss it (more on that later).
A Snap-in for All Reasons
ConsoleOne is designed to be extended to provide functionality for multiple namespaces. The namespace functionality can be whatever the namespace developer wants it to be, browsing and management being two obvious examples. Like the extensions for NetWare Administrator, ConsoleOne extensions are called snap-ins. ConsoleOne, however, provides a much higher-level of integration between its snap-ins and its shell than does NetWare Administrator.
The basic snap-in for a given namespace is called a NamespaceSnapin. So, for each namespace to be browsed or managed by ConsoleOne there will be an implementation of NamespaceSnapin to perform name context resolution within that domain. All communications to and from ConsoleOne snap-ins are done using predefined snap-in methods that the shell knows about. These methods are defined in Java interfaces. (Java interfaces are something like C++ abstract classes, in that you cannot instantiate them.)
The purpose of Java interfaces is to provide a contract between objects. In the case of a ConsoleOne snap-in, because the shell knows that your snap-in implements a ConsoleOne snap-in interface, it knows what methods to call in your snap-in and it knows that your snap-in will then do the right thing for its target namespace. Can you say polymorphism?
So then, every snap-in must implement the methods defined for it in one of ConsoleOne's snap-in interfaces (there are several different types to accomodate the different kinds of snap-ins, namespace for example). Below is an inheritance hierarchy for some of the snap-in interfaces available today, along with a one-line description of how they would be used.
java.lang.Object Snapin NamespaceSnapin - to control name context resolution in a namespace ViewSnapin - to manage how a namespace or object is displayed in the namespace view of the ConsoleOne window. DisplayImageSnapin - to provide the image for an object in a given namespace. PageSnapin - to provide object/attribute info to MPEC property book pages ToolBarSnapin - to add tool controls to ConsoleOne tool bar MenuSnapin - to add menus/menu items to ConsoleOne window. StatusBarSnapin - to display status messages in ConsoleOne status bar. ServiceSnapin - to make functionality available to other snapins.
The main ConsoleOne window is shown in Figure 1. There are two main panes in the window. The one on the left allows you to select the namespace of interest; the one on the right displays the contents of that namespace.
Figure 1: A ConsoleOne window with the NDS namespace "MyTree" displayed but unselected.
When ConsoleOne is launched, all of the namespaces are listed (including NDS trees) that this installation of ConsoleOne is configured to see. In the example shown in Figure 1, the only namespace available to the client is an NDS tree named myTree, which is currently unselected.
Figure 2: A ConsoleOne window with the NDS namespace "MyTree" selected.
In Figure 2, the user has selected the MyTree namespace. When a namespace selection is made, the contents of the namespace are displayed in the namespace view pane on the right. The objects displayed in the namespace view pane are called ObjectEntrys.
Note that when a namespace is selected, tool items specific to the namespace appear in the tools area and likewise menu extensions needed by the namespace are added. If the user were to then select a different kind of namespace, say a file system, the items from the previously selected namespace would be replaced by the items for the new one.
ConsoleOne may be a namespace browser and tool platform, but it has no specific knowledge of any particular namespace. So how does ConsoleOne accomplish all of the namespace specific things that are needed for namespace navigation?
During its launch, ConsoleOne finds out what namespace snap-ins it is configured with and in true object-oriented fashion, it lets them handle their own affairs. When ConsoleOne is launched, it looks in its root directory for another directory called snap-ins. The snap-ins directory contains all of the snap-in executables which make ConsoleOne useful. Shown in Figure 3 is the snap-ins directory in a standard ConsoleOne install.
Figure 3: Each snap-in is packaged in a JAR file. The JAR file is placed in the .\snapins directory relative to where ConsoleOne is executed.
Inside of the snap-ins directory ConsoleOne finds all of its snap-in classes contained in Java JAR files. (JAR files are zip files containing Java classes, images, and other data along with a manifest file describing the JAR's contents.) If the JAR has a manifest, ConsoleOne will read it to obtain information on all of the snap-ins it contains. If the JAR does not contain a manifest, ConsoleOne will parse each JAR file to see if it is a snap-in.
ConsoleOne loads all of the snap-ins that it finds in the JARs and then calls each of their getRegistration() methods. As shown in Figure 4, the getRegistration() method is one of the methods specified in the basic Snap-in interface. As such, it is inherited by all of Snap-in's descendant interfaces thereby requiring all snap-ins to implement this method.
Each snap-in's getRegistration( ) method provides ConsoleOne with information about what kind of snap-in it is and what namespaces and/or object types in those namespaces that it is interested in. A code-level explanation of getRegistration( ) can be found in "Snapping Your NDS App in to ConsoleOne" later in this issue. To efficiently manage memory, ConsoleOne unloads all snap-ins after the registration process is complete.
Snap-in to Shell to Snap-in Communication. After registration, snap-ins are loaded and initialized on an as-needed basis. At this point ConsoleOne knows what namespaces it is configured with. It also knows which snap-ins are registered with each namespace and object type so it can load them appropriately. However, when a snap-in is loaded it has no knowledge of ConsoleOne. To give the snap-in access to ConsoleOne functionality and to give it a chance to initialize before operation, ConoleOne immediately calls another required method, initSnapin(Shell shell) after loading the snap-in.
Access to ConsoleOne functionality is provided through the object reference to ConsoleOne's Shell object given to the snap-in with initSnapin( ). The shell object provides a wealth of accessor routines that a snap-in can then use to obtain references to other ConsoleOne objects, including the NamespaceSnapin currently selected in the browser.
The following transactions are typical of what might occur in order for ConsoleOne to obtain an appropriate view or GUI for a newly selected namespace. As you read along, find the objects and methods in the object diagram shown in Figure 4. If you can do this, you will have the necessary basic understanding of the interractions between the shell and its snap-ins.
ConsoleOne loads the view snap-in registered for the selected namespace.
shell.view.initSnapin(shell ) ConsoleOne calls view.initSnapin( ) in the newly loaded view snap-in passing it a reference to its shell object. The view snap-in saves the shell object reference in its own variable.
shell.view.getView( ) The shell calls the view snap-in's getView( ) method to obtain the GUI for the newly selected namespace.
shell.view.getView( ).shell.getTreeSelection( ) The view snap-in must get a list of ObjectEntrys in the current context in order to figure out what images to draw and where. So, the view snap-in uses its shell reference to call the shell's getTreeSelection( ) method to obtain the currently selected parent ObjectEntry (the selected ObjectEntry establishes current context). The shell returns the ObjectEntry representing the namespace since it was just selected.
shell.view.getView( ).shell.getChildren( ) The view then passes this ObjectEntry to the shell's getChildren( ) method as the parent parameter.
shell.view.getView( ).shell.getChildren( ).parent. getType( ) The shell's getChildren( ) method uses the parent ObjectEntry's getType( ) method to get an ObjectType object containing the parent's type information.
shell.view.getView( ).shell.getChildren( ).parent. type.getNameSpace( ) The shell's getChildren( ) method then calls the getNameSpace( ) method in the parent's type object to obtain an object reference to its namespace.
shell.view.getView( ).shell.getChildren ( .parentsNamespace.getChildren( ) The shell's getChildren( ) method finally calls the getChildren( ) method in the namespace object. The shell forwards the returned ObjectEntryEnumeration object (a collection of the ObjectEntrys to be displayed) back to the view.
shell.view.getView( ).shell.getDisplayImage( ) Still in its getView( ) method, for each entry in the Enumeration, the view calls the shells getDisplayImage( ) method to obtain its Image and the shell's getDisplayName( ) method to obtain its name.
shell.view.getView( ).shell.getDisplayImage( ).entry.getType( ) The shell's getDisplayImage( ) method gets an ObjectType object for each ObjectEntry.
shell.view.getView( ).shell.getDisplayImage ( ).getRegisteredDisplayImageSnapin( ) The shell's getDisplayImage( ) method then looks up the DisplayImageSnapin registered for the object type.
shell.view.getView( ).shell.getDisplayImage ( ).imgSnapin.getDisplayImage( ) The shell's getDisplayImage( ) method then calls the DisplayImageSnapin's getDisplayImage( ) method, returning the Image to the view.
shell.view.getView( ).shell.getDisplayName( ) In a similar fashion, each call to the shell's getDisplayName( ) method instantiates a registered DisplayNameSnapin object which is used to obtain a name for the view.
shell.view.getView( ) Finally, the view adds the images and names to a Java GUI Panel, arranging them in a way that it wants them displayed and returns the Panel to the ConsoleOne shell as the View Component.
shell.guiView.paint() ConsoleOne renders the Panel into the namespace view pane.
Figure 4: Simplified ConsoleOne object model diagram for discussion purposes only.
The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.