Download NetBeans!

20080227 Wednesday February 27, 2008

Getting Started Extending VisualVM (Part 2)

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.

In Getting Started Extending VisualVM (Part 1), yesterday, we used a DataSourceViewProvider to create a new DataSourceView. The latter was available to all types of applications shown in VisualVM. Today we'll create a new application type and... provide some functionality specifically for that type. First, we'll provide a new tab in the Overview section and we'll also provide a menu item, specifically for our application type.

Only those applications are recognized for which specific support has been provided. Otherwise, a default icon is shown and the default tabs are available. Let me stress at this point that for most applications, the default tabs are enough. See VisualVM: Free and Open Source Java Troubleshooter, to see what the default VisualVM provides. However, for GlassFish, or any other server, you probably want some subnodes for deployed applications. So, in scenarios where you have an application that has special needs, or for which you want to display specific information, you can (if you want to) create a new VisualVM "application type".

For this example, we will create a new application type for the Anagram Game that is bundled with the IDE. Typically, an application type is identified by its main class, which in the case of the Anagram Game is "com.toy.anagrams.ui.Anagrams". At the end, you'll have a new icon for the Anagram Game, with a new Overview tab (showing, for the sake of this simple example, a screenshot of the application), and a new "Show Anagram PID" menu item on the Anagram Game application type node, as shown in the illustration below:

The steps to take for these three entry points (i.e., application type, overview tab, and menu item), are as follows:

  1. Initialize the Entrypoints. In the module install class, as shown yesterday, initialize the three entry point implementations that you are about to create:

    package org.visualvm.demoapplicationtype;
    
    import org.openide.modules.ModuleInstall;
    
    public class Installer extends ModuleInstall {
    
        private static AnagramApplicationTypeProvider INSTANCE = new AnagramApplicationTypeProvider();
    
        @Override
        public void restored() {
            ApplicationTypeFactory.getDefault().registerProvider(INSTANCE);
        }
    
        @Override
        public void uninstalled() {
            ApplicationTypeFactory.getDefault().unregisterProvider(INSTANCE);
        }
        
    }

  2. Define the application type. Use the VisualVM Application Type Template for this purpose. As stated, we use the Anagram Game main class to determine that we want an application type to be created:

    import com.sun.tools.visualvm.application.Application;
    import com.sun.tools.visualvm.application.jvm.Jvm;
    import com.sun.tools.visualvm.application.type.ApplicationType;
    import com.sun.tools.visualvm.application.type.MainClassApplicationTypeFactory;
    
    public class AnagramApplicationTypeProvider extends MainClassApplicationTypeFactory {
    
        @Override
        public ApplicationType createApplicationTypeFor(Application app, Jvm jvm, String mainClass) {
    
            //TODO: Specify the name of the application's main class here:
            if ("com.toy.anagrams.ui.Anagrams".equals(mainClass)) {
                return new AnagramApplicationType(app.getPid());
            }
            return null;
    
        }
    
    }

    And here is the definition of the application type itself:

    import com.sun.tools.visualvm.application.type.ApplicationType;
    import java.awt.Image;
    import org.openide.util.Utilities;
    
    public class AnagramApplicationType extends ApplicationType {
    
        protected final int appPID;
    
        public AnagramApplicationType(int pid) {
            appPID = pid;
        }
    
        @Override
        public String getName() {
            return "Anagram";
        }
    
        @Override
        public String getVersion() {
            return "1.0";
        }
    
        @Override
        public String getDescription() {
            return "Application type for Anagram";
        }
    
        @Override
        public Image getIcon() {
            return Utilities.loadImage("com/sun/tools/visualvm/core/ui/resources/snapshot.png", true);
        }
    
    }

  3. Define the Overview Window Extension. Here we check that we're dealing with our application type. If so, the Overview extension is created:

    import com.sun.tools.visualvm.application.Application;
    import com.sun.tools.visualvm.application.type.ApplicationTypeFactory;
    import com.sun.tools.visualvm.application.views.ApplicationViewsSupport;
    import com.sun.tools.visualvm.core.ui.DataSourceViewPlugin;
    import com.sun.tools.visualvm.core.ui.DataSourceViewPluginProvider;
    
    class AnagramViewPluginProvider extends DataSourceViewPluginProvider<Application> {
    
        protected DataSourceViewPlugin createPlugin(Application application) {
            return new AnagramOverview(application);
        }
    
        protected boolean supportsPluginFor(Application application) {
            if (ApplicationTypeFactory.getApplicationTypeFor(application) instanceof AnagramApplicationType) {
                return true;
            }
            return false;
        }
    
        static void initialize() {
            ApplicationViewsSupport.sharedInstance().getOverviewView().
                    registerPluginProvider(new AnagramViewPluginProvider());
        }
    
        static void uninitialize() {
            ApplicationViewsSupport.sharedInstance().getMonitorView().
                    unregisterPluginProvider(new AnagramViewPluginProvider());
        }
       
    }

    And here is our new tab in the Overview window:

    import com.sun.tools.visualvm.application.Application;
    import com.sun.tools.visualvm.core.ui.DataSourceViewPlugin;
    import com.sun.tools.visualvm.core.ui.components.DataViewComponent;
    import com.sun.tools.visualvm.core.ui.components.ScrollableContainer;
    import javax.swing.JPanel;
    
    public class AnagramOverview extends DataSourceViewPlugin {
    
        AnagramOverview(Application application) {
            super(application);
        }
    
        public DataViewComponent.DetailsView createView(int location) {
            switch (location) {
                case DataViewComponent.TOP_RIGHT:
                    JPanel panel = new JPanel();
                    return new DataViewComponent.DetailsView("User Interface", null, 30,
                            new ScrollableContainer(panel), null);
                default:
                    return null;
            }
        }
    
    }

    Now we need to initialize our new tab, using the lines in bold below:

    public class Installer extends ModuleInstall {
    
        private static AnagramApplicationTypeFactory INSTANCE = new AnagramApplicationTypeFactory();
    
        @Override
        public void restored() {
            ApplicationTypeFactory.getDefault().registerProvider(INSTANCE);
            AnagramViewPluginProvider.initialize();
        }
    
        @Override
        public void uninstalled() {
            ApplicationTypeFactory.getDefault().unregisterProvider(INSTANCE);
            AnagramViewPluginProvider.uninitialize();
        }
    
    }

  4. Define the Menu Item. Use the VisualVM Action Template for this purpose. Then tweak it, if necessary, as shown below. Here, again we check for our application type and then create the menu item:

    import com.sun.tools.visualvm.application.Application;
    import com.sun.tools.visualvm.application.type.ApplicationTypeFactory;
    import com.sun.tools.visualvm.core.ui.actions.SingleDataSourceAction;
    import java.awt.event.ActionEvent;
    import javax.swing.Action;
    import javax.swing.JOptionPane;
    
    public class AnagramAction extends SingleDataSourceAction<Application> {
    
        public AnagramAction() {
            super(Application.class);
            putValue(Action.NAME, "Show Anagram PID");
            putValue(Action.SHORT_DESCRIPTION, "Demoes a menu item");
        }
    
        @Override
        protected void actionPerformed(Application application, ActionEvent arg1) {
            JOptionPane.showMessageDialog(null, application.getPid());
        }
    
        //Here you can determine whether the menu item is enabled,
        //depending on the data source type that is selected. In this
        //example, the menu item is enabled for all types within
        //the current data source:
        @Override
        protected boolean isEnabled(Application application) {
            if (ApplicationTypeFactory.getApplicationTypeFor(application) instanceof AnagramApplicationType) {
                return true;
            }
            return false;
        }
    
    }

    And here is the registration in the layer.xml file, which initializes our action as a menu item:

        <folder name="VisualVM">
            <folder name="ExplorerPopupSelection">
                <file name="org-visualvm-demoapplicationtype-AnagramAction.instance">
                    <attr name="SystemFileSystem.localizingBundle" stringvalue="org.visualvm.demoapplicationtype.Bundle"/>
                    <attr name="position" intvalue="3000"/>
                </file>
            </folder>
        </folder>

This should give you enough of a start to create your own application types with some functionality specific to the type in question.

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.

Feb 27 2008, 06:07:34 AM PST Permalink

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

Hi Geertjan,

thanks a lot for this series. I appreciate very much.

I have question about the nodes in the Applications View/Window. Do you think/know if it's possible to add additional subnodes under your application? Something like this:
- Local
-- Tomcat
-- Glassfish
-- Anagram Game
--- Anagram's subnode1
---- Anagram's subsubnode1_1
--- Anagram's subnode2

Never mind if you don't know the answer.

Thanks anyway,
Klaus

Posted by KlausStake on February 27, 2008 at 08:29 AM PST #

Hi Klaus. The answer is "Yes". If you look at the GlassFish sources (in the 'plugins' topfolder on visualvm.dev.java.net), you will see that that's already available for GlassFish. I will blog about this soon.

Posted by Geertjan on February 27, 2008 at 08:36 AM PST #

Post a Comment:

Name:
E-Mail:
URL:

Your Comment:

HTML Syntax: NOT allowed