Getting Started Extending VisualVM (Part 6)

Update on 30 May 2008: The code and steps in this blog entry have been updated to reflect the VisualVM 1.0 APIs. If you want to download the complete sources of the sample discussed here, get the VisualVM Sample Collection from the Plugin Portal.

On its most abstract level, VisualVM is simply a tool for displaying data. By default, it displays data relating to applications, hosts, dumps, and snapshots. However, it could, theoretically, display any data at all (photos, for example), although the intention of the tool is for it to deal with monitoring, troubleshooting, and management data. The reason that it can work with any kind of data is the fact that its APIs are created with pluggability in mind. Pretty much everything is pluggable and that's the point—VisualVM is intended to cater to all your monitoring, troubleshooting, and management data needs.

Each source of data (which are primarily "application", "host", "heapdump", "threaddump", "coredump", and "snapshot") is represented by a node in the explorer view. What do you need to do if you want to add another source of data there? That's what I figured out today. Here you see the Memory Monitor sample from the JDK's "demo/management" folder opened from a new "System Monitors" node in the explorer view:

The "System Monitors" node is provided by my new data source. What's also interesting is to see the "Hello World" tab above. It comes from a different module. So, in the same way that your custom views are pluggable, your custom data sources are also pluggable. Good news, right?

First, let's look at how the new node for our data source was created. We begin by extending com.sun.tools.visualvm.core.datasource.DataSource:

import com.sun.tools.visualvm.core.datasource.DataSource;

public class DemoDataSource extends DataSource {

    private static DemoDataSource sharedInstance;

    public static synchronized DemoDataSource sharedInstance() {
        if (sharedInstance == null) {
            sharedInstance = new DemoDataSource();
        }
        return sharedInstance;
    }
    
}

Next, we need to add our new DataSource to the repository of data sources. We do this when we initialize the module that provides the data source. What does this mean? It means we need to create a class that extends org.openide.modules.ModuleInstall. Instead of creating a new Java class, use the Module Install wizard, by right-clicking on the project node, choosing New | Other and then Module Development | Module Installer. Complete the wizard and then define the class as follows:

import com.sun.tools.visualvm.core.datasource.DataSource;
import org.openide.modules.ModuleInstall;

public class Installer extends ModuleInstall {

    DemoDataSource ds = DemoDataSource.sharedInstance();

    @Override
    public void restored() {
        DataSource.ROOT.getRepository().addDataSource(ds);
    }

    @Override
    public void uninstalled() {
        DataSource.ROOT.getRepository().removeDataSource(ds);
    }
    
}

We now have a new data source and added it to the repository. The next question to ask is: "How should the data source be visualized in the explorer view?" That's the purpose of the com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor class. Let's use it as follows:

import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor;
import java.awt.Image;
import org.openide.util.Utilities;

public class DemoDataSourceDescriptor extends DataSourceDescriptor<DemoDataSource> {

    //Make sure this icon exists in your module:
    private static final Image NODE_ICON =
            Utilities.loadImage(
            "org/mymodule/mypackage/mysubpackage/myicon.png",
            true);

   
    public DemoDataSourceDescriptor(DemoDataSource application) {
        super(application,
                "System Monitors",
                "Descriptor for System Monitors container",
                NODE_ICON,
                POSITION_AT_THE_END,
                EXPAND_NEVER);
    }

}

The above implies that you need to set a dependency on the NetBeans Utilities API.

We have now described how our data source will be visualized—it will have the icon and display name we set, we have specified that it should be at the end of the list of data sources and that it should not be expandable. Now how do we register the above descriptor class in our module? We need to create a VisualVM model that connect our DataSource with the above descriptor. Here's how to do that:

import com.sun.tools.visualvm.core.datasource.DataSource;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor;
import com.sun.tools.visualvm.core.model.AbstractModelProvider;

public class DemoDataSourceDescriptorProvider extends AbstractModelProvider<DataSourceDescriptor, DataSource> {

    DemoDataSourceDescriptorProvider() {
    }

    @Override
    public DataSourceDescriptor createModelFor(DataSource ds) {
        if (ds instanceof DemoDataSource) {
            return new DemoDataSourceDescriptor((DemoDataSource) ds);
        }
        return null;
    }

}

Finally, we need to initialize the descriptor provider that we created above. Go back to the Installer class and add the lines in bold below:

public class Installer extends ModuleInstall {

    DemoDataSource ds = DemoDataSource.sharedInstance();

    @Override
    public void restored() {
        DataSource.ROOT.getRepository().addDataSource(ds);
        DataSourceDescriptorFactory.getDefault().registerProvider(new DemoDataSourceDescriptorProvider());
    }

    @Override
    public void uninstalled() {
        DataSource.ROOT.getRepository().removeDataSource(ds);
        DataSourceDescriptorFactory.getDefault().unregisterProvider(new DemoDataSourceDescriptorProvider());
    }
    
}

That's all. Now run the module. VisualVM will start and you will see the new node, i.e., a top-level node, for your data source. What happens when you double-click it? Nothing. You haven't provided any functionality for your data source yet.

So, now you have a new node in the explorer view. That means that you have a new data source. As explained in Getting Started Extending VisualVM (Part 1), you can create one or more views (tabs and subtabs) for a data source. In that case, we created a tab for the application data source, yesterday we created a tab for the host data source, and today we will create one for our own new data source. Simply download and install VisualVM View template and, when you use it, type "DemoDataSource" in the Data Source field, with "Demo" as the class prefix. When you complete the wizard, make sure to initialize the new classes as described on the Plugin Portal's page.

Note: If a DataSourceViewProvider (or, in this case, the PluggableDataSourceViewProvider) returns true from the supportsViewFor() method, an "Open" menu item is automatically created for you. (I didn't know that, created my own Open menu item, and then found that I had two Open menu items, one from this plugin and one from another plugin that plugs into this data source, as explained later. Then I was told about this cool "gift" that the supportsViewFor menu item gives when returning true.)

Next, as explained in Getting Started Extending VisualVM (Part 1), use the DataSourceViewProvider.createView method to create your views. Here I followed the same steps as in that earlier blog entry, except that I copied the "Memory Monitor" sample from the JDK demo folder (which is just one class that creates a JPanel) and slightly reworked it so that it is now split across different detail subtabs.

And so, you have now created your first data source. As stated at the start, a data source is the primary actor in VisualVM. Everything that happens in VisualVM happens in relation to a data source. Now you can see how a simple example of a data source is created.

There's one more aspect to look at—the "Hello World" tab that you see in the screenshot above. How did that get there? It is not in the sources shown in the screenshot of the sources that you see above. In the same way that your own views can be made to be pluggable, as explained in Getting Started Extending VisualVM (Part 4), so your data sources have a pluggable user interface too. What I did was this—I exposed the package that contains my data source class (i.e., DemoDataSource). Then I attached it to the module suite that defines VisualVM, together with the plugin that provides the additional view. That meant I could implement DataSourceViewProvider<DemoDataSource>. Alternatively, I could implement DataSourceViewProvider<DataSource> and then check in my DataSourceViewProvider.supportsViewFor for the DemoDataSource class, exactly as done in the first plugin.

So, the code for creating a new tab for my data source is the same as before, except that it is now done in a different plugin. And, when the data source is present, the "Hello World" tab defined in DataSourceViewProvider.createView is created. The "Open" menu item is shared between the two tabs, because both return "true" from DataSourceViewProvider.supportsViewFor. Again you can see how versatile VisualVM is, because it is completely open to being extended, even to the extent that the data sources that you yourself provide can have user interfaces that can be extended by others.

Update on 30 May 2008: The code and steps in this blog entry have been updated to reflect the VisualVM 1.0 APIs. If you want to download the complete sources of the sample discussed here, get the VisualVM Sample Collection from the Plugin Portal.

Comments:

Hi, thank you for your article.

But what about removing existing datasources? I tried to remove it, but receiving the following exception:

java.lang.UnsupportedOperationException: DataSource not in repository: com.gridgain.grid.management.client.vvm.dashboard.GridVvmDashboardDataSource@180
at com.sun.tools.visualvm.core.datasource.DataSourceProvider.unregisterDataSourcesImpl(DataSourceProvider.java:154)
at com.sun.tools.visualvm.core.datasource.DataSourceContainer.unregisterDataSourcesImpl(DataSourceContainer.java:86)
at com.sun.tools.visualvm.core.datasource.DataSourceProvider$4.run(DataSourceProvider.java:124)
at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:561)
[catch] at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:986)

Posted by Slava Pedak on September 23, 2008 at 07:12 PM PDT #

Hi, this exception means that you are trying to remove a DataSource which is not in the repository. This typically happens when you are removing it twice.

If you won't be able to resolve the problem, you can get some help at users@visualvm.dev.java.net (subscription required) or feedback@visualvm.dev.java.net.

Posted by Jiri Sedlacek on September 24, 2008 at 08:32 PM PDT #

Hi,
Getting an error while trying to add multiple JMXApplications.
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
at com.sun.tools.visualvm.core.datasupport.Utils.getFilteredSet(Utils.java:111)
at com.sun.tools.visualvm.core.datasource.DataSourceProvider.getDataSources(DataSourceProvider.java:105)
at com.sun.tools.visualvm.jmx.application.JmxApplicationProvider.addJmxApplication(JmxApplicationProvider.java:214)
at com.sun.tools.visualvm.jmx.application.JmxApplicationProvider.createJmxApplication(JmxApplicationProvider.java:192)
at com.sun.tools.visualvm.jmx.JmxApplicationsSupport.createJmxApplicationImpl(JmxApplicationsSupport.java:211)
at com.sun.tools.visualvm.jmx.JmxApplicationsSupport.createJmxApplicationInteractive(JmxApplicationsSupport.java:189)
at com.sun.tools.visualvm.jmx.JmxApplicationsSupport.createJmxApplicationInteractive(JmxApplicationsSupport.java:147)
at DiscoveryPlugin.Installer$1.run(Installer.java:34)
at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:572)
at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:997)

My restored method looks like this
----------------------------------------
public void restored() {
final DiscoveryAgent agent =new DiscoveryAgent();
agent.discoverAll();
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
try {
for(final Process pm : agent.getProcess()){
JmxApplicationsSupport.getInstance().createJmxApplicationInteractive(pm.getJmxUrl(), pm.getProcessId(),null, null);
}
} catch(Throwable t){
t.printStackTrace();
}
}
});
}

Posted by Biswaranjan Das on December 26, 2008 at 02:19 AM PST #

This looks like a bug in VisualVM 1.1. Could you please file a bug report (https://visualvm.dev.java.net/issues/enter_bug.cgi?issue_type=DEFECT) and provide more details there? At least the full logfile and the above code is needed, but some sample code which reproduces this problem would help much more. Thanks!

Posted by Jiri Sedlacek on December 26, 2008 at 04:23 PM PST #

Thanks for the article.

Is there any way to extend or use the graphic panels(charts) used in the Visual VM, instead of plotting our charts?

I couldn't find it in the quickstart..

Posted by onura on August 24, 2009 at 01:39 AM PDT #

The View template from the plugin portal does not install in NB 6.8, it says the following and next is disabled:

Some plugins require plugin NetBeans Module Projects to be installed.
The plugin NetBeans Module Projects is requested in implementation version 6. The following plugins are affected:       VisualVM Action       VisualVM Application       VisualVM View
Some plugins require plugin TAX Library to be installed.
The plugin TAX Library is requested in implementation version 4. The following plugins are affected:       VisualVM Action       VisualVM Application       VisualVM View

Is there anything I can do to solve this?

Posted by Dietrich Schulten on June 25, 2010 at 02:48 PM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today