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.

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 12: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 12:36 AM PST #

It would be very nice if jvisualvm could ask the application for an icon and a description (fine with the actual class in parenthesis after), since this will allow us to ask the users to use jvisualvm without any configuration and we would like to see some runtime information.

Posted by Thorbjørn Ravn Andersen on August 26, 2009 at 04:26 AM PDT #

Hi,

Very new to VislualVM, so i got stuck on the layer.xml part. Where do i find that file or do i have to create it?

Thank you
Winston

Posted by Winston on November 24, 2010 at 09:08 PM PST #

When you create a new module, there's a checkbox for creating the layer.xml file.

Posted by Geertjan Wielenga on November 24, 2010 at 09:19 PM PST #

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
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today