Download NetBeans!

20080301 Saturday March 01, 2008

Getting Started Extending VisualVM (Part 5)

Until now, we've only dealt with applications in the context of VisualVM. But applications are only one source of data for VisualVM. There are a few others, one of which is "Host". That is a class that provides the common interface for data sources that represent a localhost or remote host. In the same way as you can extend the Application view, by adding new tabs similar to the "Overview" tab and the "Monitor" tab, you can also extend the Host view. Here you see a new tab in the Host view, called "Hello World":

And here is a new subtab, called "Friendly Greeting", that I added to the Overview tab in the Host view:

And here is all the code. First, here's the factory class that will create our tab in the Host view:

package org.visualvm.demopluggableview;

import com.sun.tools.visualvm.core.datasource.Host;
import com.sun.tools.visualvm.core.ui.DataSourceView;
import com.sun.tools.visualvm.core.ui.DataSourceViewsProvider;
import com.sun.tools.visualvm.core.ui.DataSourceWindowFactory;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class DemoDataSourceViewsProvider implements DataSourceViewsProvider<Host> {

    private final Map<Host, DataSourceView> viewsCache = new HashMap();
    
    private static DataSourceViewsProvider HelloWorldViewProvider = 
            new DemoDataSourceViewsProvider();

    @Override
    public boolean supportsViewFor(Host host) {
        //Always shown:
        return true;
    }

    @Override
    public synchronized Set getViews(
            final Host host) {
        
        DataSourceView view = viewsCache.get(host);
        if (view == null) {
            view = new DemoDataSourceView(host) {
                @Override
                public void removed() {
                    super.removed();
                    viewsCache.remove(host);
                }
            };
            viewsCache.put(host, view);
        }

        return Collections.singleton(view);
    }

    static void initialize() {
        DataSourceWindowFactory.sharedInstance().addViewProvider(
                HelloWorldViewProvider, Host.class);
    }
    
    static void unregister() {
        DataSourceWindowFactory.sharedInstance().removeViewProvider(
                HelloWorldViewProvider);
    }
    
}

Take note of the fact that above we refer to the "Host.class", instead of the "Application.class", as was done previously. Also, we are implementing DataSourceViewsProvider<Host>, instead of DataSourceViewsProvider<Application>. The view that is created is the same as before, except that the Host class is received instead of the Application class:

package org.visualvm.demopluggableview;

import com.sun.tools.visualvm.core.datasource.Host;
import com.sun.tools.visualvm.core.ui.DataSourceView;
import com.sun.tools.visualvm.core.ui.components.DataViewComponent;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JEditorPane;
import org.openide.util.Utilities;

class DemoDataSourceView extends DataSourceView {

    private DataViewComponent dvc;
    private Host host;
    private DataViewComponent view;
    private static final String IMAGE_PATH = "" +
            "org/visualvm/demopluggableview/icon.png"; // NOI18N

    public DemoDataSourceView(Host host) {
        super("Hello World", new ImageIcon(
                Utilities.loadImage(IMAGE_PATH, true)).getImage(), 60);
        this.host = host;
    }

    @Override
    public DataViewComponent getView() {
        if (view == null) {
            view = createViewComponent();
        }
        return view;
    }

    private DataViewComponent createViewComponent() {

        //Data area for master view:
        JEditorPane generalDataArea = new JEditorPane();
        generalDataArea.setBorder(BorderFactory.createEmptyBorder(14, 8, 14, 8));

        //Master view:
        DataViewComponent.MasterView masterView = 
                new DataViewComponent.MasterView("Hello World Overview", 
                null, generalDataArea);

        //Configuration of master view:
        DataViewComponent.MasterViewConfiguration masterConfiguration =
                new DataViewComponent.MasterViewConfiguration(false);

        //Add the master view and configuration view to the component:
        dvc = new DataViewComponent(masterView, masterConfiguration);

        return dvc;

    }
    
}

Next, we'll create the subtab, i.e., as shown in the second screenshot above. Again, first the factory class, which also uses the Host class, instead of the Application class:

package org.visualvm.demosubtab;

import com.sun.tools.visualvm.core.datasource.Host;
import com.sun.tools.visualvm.core.dataview.overview.OverviewViewSupport;
import com.sun.tools.visualvm.core.ui.ViewPlugin;
import java.util.Collections;
import java.util.Set;

public class DemoViewPlugin implements ViewPlugin<Host> {

    private static final DemoViewPlugin INSTANCE = new DemoViewPlugin();

    public Set getAreasFor(Host host) {
        return Collections.EMPTY_SET;
    }

    public Set getViewsFor(Host host) {
        return Collections.singleton(new DemoViewDescriptor());
    }

    public static void initialize() {
        OverviewViewSupport.getInstance().getHostPluggableView().
                addPlugin(INSTANCE, Host.class);
    }

    public static void shutdown() {
        OverviewViewSupport.getInstance().getHostPluggableView().
                removePlugin(INSTANCE);
    }
    
}

And then our view, which is unchanged, i.e., it would be the same, whether it is used in the Application view or in the Host view:

package org.visualvm.demosubtab;

import com.sun.tools.visualvm.core.ui.ViewPlugin.ViewDescriptor;
import com.sun.tools.visualvm.core.ui.components.DataViewComponent;
import com.sun.tools.visualvm.core.ui.components.DataViewComponent.DetailsView;
import java.awt.BorderLayout;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class DemoViewDescriptor implements ViewDescriptor {

    public DetailsView getView() {

        //Create JPanel:
        JPanel panel = new JPanel(new BorderLayout());
        panel.setOpaque(false);
        
        //Add JEditorPane:
        final JEditorPane area = new JEditorPane();
        area.setOpaque(false);
        panel.add(area, BorderLayout.CENTER);
        
        //Add label with pic:
        JLabel label = new JLabel();
        label.setText("--- hello world hello world hello world ---");
        panel.add(label);

        //Add JPanel:
        DataViewComponent.DetailsView details = new DataViewComponent.DetailsView(
                "Friendly Greeting",
                "Picture representing the user interface",
                panel,
                null);

        return details;

    }

    public int getLocation() {
        return DataViewComponent.TOP_RIGHT;
    }

    public int getPreferredPosition() {
        return 0;
    }

}

If, instead of "TOP_RIGHT", you set "BOTTOM_RIGHT", in getLocation(), the new subtab will appear below the existing subtabs, so you have quite a few options in determining how exactly you want to extend the existing tab.

And that's how you can extend the Host view in VisualVM.

Mar 01 2008, 11:55:23 AM PST Permalink

Trackback URL: http://blogs.sun.com/geertjan/entry/getting_started_extending_visualvm_part3
Comments:

Post a Comment:

Name:
E-Mail:
URL:

Your Comment:

HTML Syntax: NOT allowed