Consortium    Solutions    Middleware    Forge    MyObjectWeb 
ObjectWeb Consortium
Print

Advanced - Powered by Google






OpenCCM

Project Links
· Home
· Download
· Documentation
· Mailing Lists
· Wiki
· Partners
· License
· History
· Related projects

Developers' Corner
· How to Contribute
· Workplan
· Resources
· CVS Repository
· Bug Tracking
· ObjectWeb Forge Site
· User Mailing List
· Team Mailing List

About
· Team
· Contacts

Table of Contents

  1. The Browser Framework
  2. How to customize your console?
  3. How to write your own plugin?
    1. How to write a wrapper?
    2. How to write a panel?
    3. How to write an icon provider?
    4. How to write a contextual menu?
    5. How to write a Drag and Drop action?
    6. How to write a class providing information?
    7. What is a TreeView?
  4. How to build a console
  5. The Browser framework configuration
  6. Existing console examples

The Browser Framework

A Generic Framework

The main goal of the generic browser framework is to provide a monitoring and management console which allows users to browse and to interact with any kind of objects. This framework is generic as it can be configured using a specific XML DTD grammar and extended by developing plug-ins compliant with the Application Programming Interfaces (API) defined by the Browser framework.

This framework is defined in order to provide an entity able to browse a set of resources. The best adapted representation for such manipulation is a tree structure. The tree GUI allows users to dynamically discover its structure by using the mechanism of wrappers: If a wrapper is defined for an entity type, the browser requests the given wrapper for obtaining the children entities. Each entity is represented as a node of the tree. So, the developer of plug-in determines the children of a specific entity.

This framework is designed in order to be:

  • Customizable/Extensible: Users can personalize the Browser framework via an XML based language and some plug-ins.
  • Independent from technologies: You can develop plug-ins for any Java technologies.
  • Non-intrusive: The Browser does not impose any modification to the leverage application to manage.
  • Abstraction of the GUI aspects: You can write your own plug-in without worrying about graphical aspects. The framework is in charge of those graphical aspects. You just have to write your business code.
  • Composable: Users can compose their own consoles by assembling several configurations (plug-ins).

The following list provides all customizable elements for each entity:

  • The jar files containing the resources loaded by the Java Virtual Machine and used by the plug-in. In other words, it can be either the archive representing the plug-in or an archive containing the manageable entities.
  • The wrapper to use for browsing the resource: This class wraps the manipulated resource in order to discover its children. For example, the wrapper of a naming service provides all objects bound to it.
  • The icon to visually represent the object into the console.
  • A panel to display distinctive information about the resource.
  • A contextual menu to act on the resource. It defines a set of actions available for users.
  • An action to execute on Drag&Drop.
  • A short description displayed in the status bar.

Architectural View

The following picture provides a global view of the architecture of the generic browser framework:

The Browser architecture

A console built using this framework is mainly composed of two elements:

  • The implementation of the framework which is in charge of the main graphical aspects (Tree view, Drag&Drop support, ...), the configuration parsing and the characteristics resolution.
  • One or more plug-ins defining the behaviours of the console.

To sum up, the provided Browser framework does nothing alone. But you can add every kind of behaviours using the mechanism of plug-ins.

User View

Here is an example of an instance of the generic Browser framework:

The OpenCCM Management Console

The Browser framework is at least composed of a "tree panel" which browses what ever you wish. Moreover, you can plug a "View panel" and a "Status Bar" on this tree panel in order to have a complete console.

How to customize your console?

As we have ever seen in the section presenting the architectural view of the generic Browser, this framework uses plug-ins to feed itself. The following picture presents the contents of a plug-in.

The plug-in architecture

A plug-in is a logical entity which provides a behaviour for the Browser framework. It is composed of one or several Jar archives. It contains the set of resources customizing one or more entities (The "entities" word means different types of objects or components). So, we can find in such an archive a set of Java classes compliant with the API defined by the Browser framework (for wrappers, for panels, for actions, ...) and a set of files (icon files, configuration files).

The XML configuration files represent the link between the framework and the plug-in. Those files allow the Browser to associate a configuration to a given type of object.

How to write your own plugin?

This part describes the way to create a new plug-in. Several interfaces have been defined in order to write a plug-in. There is at least one interface per customizable element. All those interfaces can be found in the org.objectweb.util.browser.api package of the Browser framework archive.

In this section, we will create a very simple plug-in for managing java.util.Map objects. Through this example, any elements that can be configured with this framework will be covered. Of course, all those elements are independent and they are not required together in the same configuration. For example, you can customize an icon for a specific object without specifying any other elements (panel, menu item, wrapper, ...). In a first time, we will create all the classes included in the plug-in and in the following part, we will configure the way to use this plug-in.

The following picture is in fact the result we want to obtain by browing a java.util.Map instance.

The java.util.Map example

The complete plug-in example is available in the example/map directory of the browser module. This example can be executed using the ant tool. The compile Ant task compiles the map plug-in, and the run task executes a example of console using this plug-in. Of course, the Browser framework has to be built before compiling and running this example.

How to write a wrapper?

What is a wrapper?

A wrapper is an entity able to browse a type of objects. It wraps the object you want to manipulate and provides the children of this object which will be displayed in the tree. So, the plug-in's developer determines the children of the selected object.

The implementation class can be configured by using the wrapper element.

API

The Wrapper API The Context API

Two interfaces have been defined in order to create a wrapper:

  • The first one (named Wrapper) to have access to the wrapped object.
  • The second one (named Context) to provide the list of children to display. The returned type is an array of entries (org.objectweb.util.browser.api.Entry). An entry is a simple structure containing a name, an associated value and a context.

Example

public class MapContext
  implements Wrapper, Context
{

    /** The reference of the map to browse. */
    protected java.util.Map map_;

    /**
     * Sets the wrapped object.
     */
    public void setWrapped(Object object)
    {
        map_ = (java.util.Map)object;
    }

    /**
     * Gets the wrapped object.
     */
    public Object getWrapped()
    {
        return map_;
    }

    /**
     * Returns an array of Entry representing the mappings contained in this map.
     * @return The entries of the context.
     */
    public Entry[] getEntries()
    {
        // Creates the array of entries.
        Entry[] entries = new Entry[map_.size()];

        // Populates the array with the mappings contained in the map.
        Object[] keys = map_.keySet().toArray();
        Object[] elements = map_.values().toArray();
        for (int i = 0; i < entries.length; i++)
        {
            entries[i] =
              new DefaultEntry(elements[i],
                new DefaultName(keys[i].toString()), this);
        }
        return entries;
    }

}

In this example, the wrapper provides the list of mappings contained in a given java.util.Map.

How to write a panel?

What is a panel?

A panel is an element which displays information about the selected resource in the tree. A panel may be a simple Panel implementation or it may be composed of several view objects (a list of Panel instances and/or Table instances).

This class can be configured by using the panel element.

API

The View APIs

Concerning the Panel interface, the first called method is the one which allows the developer to initialize the panel depending on the selected object (selected()). Then, the tree obtains the panel by calling the getPanel() method. And finally, when another node is selected, the tree notifies the current panel (unselected()). So, you can for example save the filled data of the panel.

The other supported view element for the moment is the Table element. When you want to create a table, you just have to provide the headers of the table (getHeaders() method) and the set of rows of the table (getRows() method). Of course, the number of columns of the headers array and the rows array must be the same. So, the tree is in charge of the data display, the icon search and the contextual menu search for each selected cell.

Example

In this example, the "view panel" is composed of a panel which provides a title and a table which lists the values of the selected map.

The first code example is a Panel implementation and provides the title of the main panel:

public class MapTitlePanel
  implements Panel
{

    /** The panel to provide */
    protected javax.swing.JPanel panel_;

    /**
     * Creates a panel with a title displaying the map size.
     */
    public void selected(TreeView treeView)
    {
        // Obtains the selected map.
        java.util.Map map = (java.util.Map)treeView.getSelectedObject();

        // Creates and customizes the panel.
        panel_ = new JPanel();
        panel_.setBackground(java.awt.Color.WHITE);
        panel_.add(
          new javax.swing.JLabel("Map Entries (" + map.size() + " entries)")
        );
    }

    /**
     * Returns the title panel.
     */
    public JPanel getPanel()
    {
        return panel_;
    }

    /**
     * When unselected.
     */
    public void unselected(TreeView treeview)
    {
        // Nothing to do !
    }

}

It just initializes a panel containing the size of the map in the selected() method and provides this panel in the getPanel() method.

The second example is a Table implementation and provides the data contained in the selected map:

public class MapTable
  implements Table
{

    /**
     * Returns the table headers.
     */
    public String[] getHeaders(TreeView treeView)
    {
        return new String[]{"Keys","Values"};
    }

    /**
     * Returns the rows of the table.
     * Provides the list of elements contained in the map.
     */
    public Object[][] getRows(TreeView treeView)
    {
        // Obtains the selected Map.
        java.util.Map map = (java.util.Map)treeView.getSelectedObject();

        // Obtains the map entries.
        java.util.Map.Entry[] elements =
         (java.util.Map.Entry[])map.entrySet().toArray(new java.util.Map.Entry[0]);

        // Creates the array of entries.
        Object[][] mappings = new Object[map.size()][2];
        for (int i = 0; i < elements.length; i++) {
            mappings[i] =
              new Object[]{elements[i].getKey(),
                           new DefaultEntry(elements[i].getValue(),
                             new DefaultName(elements[i].getKey().toString()))};
        }
        return mappings;
    }

}

The class requests the selected map to obtain its mappings and provides an array of entries containing those mappings.

How to write an icon provider?

What is an icon provider?

An icon provider is a class able to provide an icon which could be computed according to the state of the given object.

The other way to configure an icon for a specific node is to directly provide the URL of an icon file in a configuration file. (See the icon element for more details).

API

The Icon Provider API

This interface is very simple as it contains only one method to obtain an icon for the parameter object.

Example

public class MapIconProvider
  implements IconProvider
{

    /**
     * Returns a javax.swing.Icon according to the given object.
     * Provides an icon representing the size of the given java.util.Map.
     */
    public Icon newIcon(Object object)
    {
        java.util.Map map = (java.util.Map)object;
        return new NumberIcon(map.size());
    }

}

This class provides an icon containing a number representing the size of the java.util.Map. This number is in fact the number of mappings contained in this map.

How to write a contextual menu?

What is a contextual menu?

A contextual menu is a menu which is displayed when the user right-clicks on a specific node. A contextual menu is composed of a set of items. Each item has to implement the MenuItem interface.

A contextual menu can inherit from superclass menus. In other words, you can define actions for a high level class or interface type (named C), and when the tree will display a popup menu for a subclass of the C class (at the Java type inheritance level), it will inherit actions defined for C class. Moreover, each item can be defined directly for the selected object or for its children at the graphical tree level. Indeed, some actions are simplier to use when they are visible by the children of the selected resource. For example, it's simplier to use an action which removes an entry from a map when you can directly select the entry you want to remove. For more information on the way to configure this features, have a look to the menu section and the item section of the Browser descriptor page.

A contextual menu can be configured by using the menu element.

API

The Menu Item API

Concerning the MenuItem interface, the first called method is the getStatus() because it allows to compute the status of the menu item depending on the state of the selected object. By the way, you can create disabled button (MenuItem.DISABLE_STATUS) but also makes it invisible (MenuItem.NOT_VISIBLE_STATUS). For example, this feature may be useful for managing component's life cycle. The "stop" action is enabled only if the component is already started. So, you can prevent exception management because you disable the action instead of manage exception when the action is used in a bad context. But most of the time, you want the button is accessible (MenuItem.ENABLE_STATUS). The second method, named actionPerformed(), represents the action which is executed when the user activates the corresponding menu.

The framework offers a simple exception management which just displays the thrown exception in a dialog box, so you might not care about exceptions throwable in your business code.

Example

Here is an example of action directly used by java.util.Map object:

public class MapClearAction
  implements MenuItem
{

    /**
     * This item is enabled only if the map contains at least one entry.
     */
    public int getStatus(TreeView treeView)
    {
        // Obtains the selected map.
        java.util.Map map = (java.util.Map)treeView.getSelectedObject();

        // Item enabled if this map contains at least one entry.
        if (map.size()>0)
            return MenuItem.ENABLED_STATUS;
        return MenuItem.DISABLED_STATUS;
    }

    /**
     * Removes all the mappings from this map.
     */
    public void actionPerformed(MenuItemTreeView treeView)
    throws Exception
    {
        // Obtains the selected map.
        java.util.Map map = (java.util.Map)treeView.getSelectedObject();

        // Removes all entries from this map.
        map.clear();
    }

}

This simple example class removes all the mappings of the selected Map. It just consists in obtaining the selected map and calling the clear() method on this map.

The following example is an action defined for the children of the java.util.Map object provided by the Wrapper class:

public class MapRemoveEntryAction
  implements MenuItem
{

    /**
     * Returns enabled status.
     */
    public int getStatus(TreeView treeView)
    {
          return MenuItem.ENABLED_STATUS;
    }

     /**
     * Removes the mapping for this key from this map.
     */
    public void actionPerformed(MenuItemTreeView treeView)
    throws Exception
    {
        // Obtains the selected map.
        Map map = (Map)treeView.getParentObject();

        // Obtains the entry to remove.
        Object objectToRemove = treeView.getSelectedEntry().getName();

        // Removes the entry.
        map.remove(objectToRemove);
    }

}

This class removes the selected entry from its map. It consists in

  1. Obtaining the map from which the entry has to be removed.
  2. Obtaining the selected entry.
  3. Removing the selected entry.

How to write a Drag&Drop action?

What is a Drag&Drop action?

The DropAction interface is used to define action in Drag&Drop context. This interface is instantiated when the user drops an element on a specific node. This interface is defined for the target node which is selected during the drop action.

This class can be configured by using the drop-action element.

API

The Drag and Drop action API

This interface contains only one method which is called when the user drops an object on a specific node.

Example

public class MapAddObjectOnDropAction
  implements DropAction
{

    /**
     * Adds a new entry in the given map.
     */
    public void execute(DropTreeView dropTreeView)
    throws Exception
    {
        // Obtains the selected Map.
        java.util.Map map = (java.util.Map)dropTreeView.getSelectedObject();

        // Obtains the drag entry to add.
        Object objectKey = dropTreeView.getDragSourceEntry().getName();
        Object objectToAdd = dropTreeView.getDragSourceObject();

        // Adds the entry.
        map.put(objectKey, objectToAdd);
    }

}

This example adds a mapping into the Map on which the user decides to drop the drag object. It consists in:

  1. Obtaining the selected Map. It is in fact the object on which the user drops the dragged object.
  2. Obtaining the entry to add. In other words, obtaining the drag source.
  3. Adding the dragged source entry into the dropped target map.

How to write a class providing information?

What is the Info interface?

The goal of the Info interface is to provide a short description of an entity. This description will be displayed in the "Status Bar".

This class can be configured by using the info element.

API

The Info API

This interface contains only one method which is called when a node is selected and such an interface is defined for this kind of node.

Example

public class MapInfo
  implements Info
{

    /**
     * Provides the number of entries of the given map.
     */
    public String getInfo(TreeView treeView)
    {
        // Obtains the selected Map.
        java.util.Map map = (java.util.Map)treeView.getSelectedObject();

        // Returns the map size.
        return new String("Map size: " + map.size() + " entries");
    }

}

This simple example indicates the number of mappings contained in the selected map.

What is a TreeView?

API

Those interfaces are provided by the tree and represent the state of the tree at a certain point during execution.

The TreeView API

Those objects represent parameters for many methods of plug-in interfaces. The most general interface (named TreeView) allows to obtain information about the tree. For example, you can obtain the selected node and its parent. You can also, via this interface, add new entry into the tree, or also, refresh the tree.

Concerning the Drag&Drop, another information is required: The source object on which the Drag&Drop mechanism has been initialized, that's why the interface used is the DropTreeView interface.

How to build your console

This part deals with the assembling of a console. It presents a code example which allows you to create a console to illustrate the Map plug-in.

public class Main
{

    public static void main(String[] args)
    {
        // Creates the main frame.
        JFrame frame = new JFrame("Browser GUI");

        // Creates the view panel.
        ViewPanel viewPanel = new DefaultViewPanel();

        // Creates the status bar.
        StatusBar statusBar = new DefaultStatusBar();

        // Creates the tree.
        DynamicTree tree = new DynamicTree();

        // Populates the tree.
        tree.addEntry("Object 1", new Object());
        tree.addEntry("Object 2", new Object());
        tree.addEntry("Map", new java.util.HashMap());

        // Configures the tree.
        tree.setNewBrowserProperty(new String[]{args[0]});
        tree.setTargetPanel(viewPanel);
        tree.setStatusBar(statusBar);

        // Configures the main frame.
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(new DefaultTreePanel((DynamicTree)tree),
            BorderLayout.CENTER);
        frame.getContentPane().add(((DefaultViewPanel)viewPanel), BorderLayout.EAST);
        frame.getContentPane().add((DefaultStatusBar)statusBar, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

}

This example creates a complete console divided into three parts: a tree view, a status bar and a view panel. It consits on creating all the elements, configuring the tree, and connecting them together.

The important points in this peace of code are the tree configuration and the tree filling up.

The Browser Framework Configuration

In order to configure your plug-in, you can have a look at the Browser descriptor page which presents all the elements of the Browser configuration grammar.

The following example represents a configuration for a specific node (java.util.Map):

<node type-name="java.util.Map">
  <jar url="file:build/lib/map-plugin.jar" />
  <wrapper>
    <code>org.objectweb.util.browser.plugins.java.MapContext</code>
  </wrapper>
  <icon>
    <code>org.objectweb.util.browser.plugins.java.MapIconProvider</code>
  </icon>
  <panel>
    <panel>
      <code>org.objectweb.util.browser.plugins.java.MapTitlePanel</code>
    </panel>
    <table>
      <code>org.objectweb.util.browser.plugins.java.MapTable</code>
    </table>
  </panel>
  <menu>
    <item label="Clear this map">
      <code>org.objectweb.util.browser.plugin.java.map.MapClearAction</code>
      <accelerator ctrl="true" char="c" />
    </item>
    <item label="Delete this entry" tree-child-visible="true">
      <code>org.objectweb.util.browser.plugin.java.map.MapRemoveEntryAction</code>
      <icon><icon-file url="delete.png" /></icon>
      <accelerator ctrl="true" char="d" />
      <mnemonic char="d" />
    </item>
  </menu>
  <drop-action label="Add an object">
    <code>org.objectweb.util.browser.plugins.java.MapAddObjectOnDropAction</code>
  </drop-action>
  <info>
    <code>org.objectweb.util.browser.plugins.java.MapInfo</code>
  </info>
</node>

This configuration allows one to obtain the following graphical representation when browsing a java.util.Map instance:

The java.util.Map example

We find again all the elements we have defined in the previous sections and we have specified in the XML declaration. The Drag&Drop action allows one to add mappings into the map and when you select this map, you can see the information displayed as defined in the configuration.

Moreover, you can notice that the Jar archive containing the plug-in classes has been specified in the XML configuration. So, it is not required to add this archive into the classpath used to launch the console.

How does it work ?

When a Browser framework instance looks for a configuration for a selected node, it first looks for the configuration using the more specific object type (java.util.HashMap in our case) and if no configuration is found, it computes the inheritance tree of the given object (as shown in the following picture) and for each classes of the tree, it queries for a configuration for the given class. That's why the configuration defined for java.util.Map interface is applied to java.util.HashMap object.

The java.util.HashTable tree inheritance

Existing Console Examples

The following list presents some projects which use the Browser framework in order to provide a graphical console. In fact, these are various instances of the Browser framework.

The OpenCCM Management Console
  • OpenCCM Management Console: The OpenCCM Browser is a graphical console tool for browsing and interacting with CORBA components at runtime. This browser allows you to browse the CosNaming Service, the CosTrading Service, and the Interface Repository if they are started. For example, you can deploy an application step by step, create components, connect them together, introspect components connections.
The OpenCCM Assembling Console
  • OpenCCM Packaging and Assembling tools: OpenCCM provides Graphical User Interfaces to help developers writing the meta information needed by a CCM XML deployment. Thanks to this graphical tool, you can easily browse the XML elements you have to inform in order to build a CCM application.
The apollon browser screenshot
  • Apollon project: Apollon is a generation engine able to build graphical user interfaces (GUI) from XML DTDs and customization models. This makes the GUIs adapted to the edition of XML documents.
    In this case, all the plug-ins are generated according to the XML DTD.
The GoTM browser screenshot
  • GoTM: The idea behind GoTM is to support a rich set of core services allowing to build various personalities compliant to advanced transaction models or existing industrial standards. GoTM is based on the Fractal Component Model. This console allows users to browse Fractal Components and more precisely to navigate through those components interfaces and act on them.
The Java reflector screenshot
  • Java reflector plug-in: This console allows users to browse a Jar archive, its packages and for each class of a package, displays its fields, methods and inner classes. It also displays the Java class inheritance tree.
    The associated plug-in can be found in the example/reflector directory of the browser module.

Copyright © 1999-2005, ObjectWeb Consortium | contact | webmaster | Last modified at 2005-07-07 02:04 PM