0N/A/*
2362N/A * Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.tools.jconsole;
0N/A
0N/Aimport java.beans.PropertyChangeEvent;
0N/Aimport java.beans.PropertyChangeListener;
0N/Aimport java.util.ArrayList;
0N/Aimport java.util.List;
0N/Aimport javax.swing.JPanel;
0N/Aimport javax.swing.SwingWorker;
0N/A
0N/A/**
0N/A * A JConsole plugin class. JConsole uses the
0N/A * <a href="{@docRoot}/../../../../api/java/util/ServiceLoader.html">
0N/A * service provider</a> mechanism to search the JConsole plugins.
0N/A * Users can provide their JConsole plugins in a jar file
0N/A * containing a file named
0N/A *
0N/A * <blockquote><pre>
0N/A * META-INF/services/com.sun.tools.jconsole.JConsolePlugin</pre></blockquote>
0N/A *
0N/A * <p> This file contains one line for each plugin, for example,
0N/A *
0N/A * <blockquote><pre>
0N/A * com.sun.example.JTop</pre></blockquote>
0N/A * <p> which is the fully qualified class name of the class implementing
0N/A * {@code JConsolePlugin}.
0N/A *
0N/A * <p> To load the JConsole plugins in JConsole, run:
0N/A *
0N/A * <blockquote><pre>
0N/A * jconsole -pluginpath &lt;plugin-path&gt; </pre></blockquote>
0N/A *
0N/A * <p> where <tt>&lt;plugin-path&gt;</tt> specifies the paths of JConsole
0N/A * plugins to look up which can be a directory or a jar file. Multiple
0N/A * paths are separated by the path separator character of the platform.
0N/A *
0N/A * <p> When a new JConsole window is created for a connection,
0N/A * an instance of each {@code JConsolePlugin} will be created.
0N/A * The {@code JConsoleContext} object is not available at its
0N/A * construction time.
0N/A * JConsole will set the {@link JConsoleContext} object for
0N/A * a plugin after the plugin object is created. It will then
0N/A * call its {@link #getTabs getTabs} method and add the returned
0N/A * tabs to the JConsole window.
0N/A *
0N/A * @see <a href="{@docRoot}/../../../../api/java/util/ServiceLoader.html">
0N/A * java.util.ServiceLoader</a>
0N/A *
0N/A * @since 1.6
0N/A */
0N/Apublic abstract class JConsolePlugin {
0N/A private volatile JConsoleContext context = null;
0N/A private List<PropertyChangeListener> listeners = null;
0N/A
0N/A /**
0N/A * Constructor.
0N/A */
0N/A protected JConsolePlugin() {
0N/A }
0N/A
0N/A /**
0N/A * Sets the {@link JConsoleContext JConsoleContext} object representing
0N/A * the connection to an application. This method will be called
0N/A * only once after the plugin is created and before the {@link #getTabs}
0N/A * is called. The given {@code context} can be in any
0N/A * {@link JConsoleContext#getConnectionState connection state} when
0N/A * this method is called.
0N/A *
0N/A * @param context a {@code JConsoleContext} object
0N/A */
0N/A public final synchronized void setContext(JConsoleContext context) {
0N/A this.context = context;
0N/A if (listeners != null) {
0N/A for (PropertyChangeListener l : listeners) {
0N/A context.addPropertyChangeListener(l);
0N/A }
0N/A // throw away the listener list
0N/A listeners = null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the {@link JConsoleContext JConsoleContext} object representing
0N/A * the connection to an application. This method may return <tt>null</tt>
0N/A * if it is called before the {@link #setContext context} is initialized.
0N/A *
0N/A * @return the {@link JConsoleContext JConsoleContext} object representing
0N/A * the connection to an application.
0N/A */
0N/A public final JConsoleContext getContext() {
0N/A return context;
0N/A }
0N/A
0N/A /**
0N/A * Returns the tabs to be added in JConsole window.
0N/A * <p>
0N/A * The returned map contains one entry for each tab
0N/A * to be added in the tabbed pane in a JConsole window with
0N/A * the tab name as the key
0N/A * and the {@link JPanel} object as the value.
0N/A * This method returns an empty map if no tab is added by this plugin.
0N/A * This method will be called from the <i>Event Dispatch Thread</i>
0N/A * once at the new connection time.
0N/A *
0N/A * @return a map of a tab name and a {@link JPanel} object
0N/A * representing the tabs to be added in the JConsole window;
0N/A * or an empty map.
0N/A */
0N/A public abstract java.util.Map<String, JPanel> getTabs();
0N/A
0N/A /**
0N/A * Returns a {@link SwingWorker} to perform
0N/A * the GUI update for this plugin at the same interval
0N/A * as JConsole updates the GUI.
0N/A * <p>
0N/A * JConsole schedules the GUI update at an interval specified
0N/A * for a connection. This method will be called at every
0N/A * update to obtain a {@code SwingWorker} for each plugin.
0N/A * <p>
0N/A * JConsole will invoke the {@link SwingWorker#execute execute()}
0N/A * method to schedule the returned {@code SwingWorker} for execution
0N/A * if:
0N/A * <ul>
0N/A * <li> the <tt>SwingWorker</tt> object has not been executed
0N/A * (i.e. the {@link SwingWorker#getState} method
0N/A * returns {@link javax.swing.SwingWorker.StateValue#PENDING PENDING}
0N/A * state); and</li>
0N/A * <li> the <tt>SwingWorker</tt> object returned in the previous
0N/A * update has completed the task if it was not <tt>null</tt>
0N/A * (i.e. the {@link SwingWorker#isDone SwingWorker.isDone} method
0N/A * returns <tt>true</tt>).</li>
0N/A * </ul>
0N/A * <br>
0N/A * Otherwise, <tt>SwingWorker</tt> object will not be scheduled to work.
0N/A *
0N/A * <p>
0N/A * A plugin can schedule its own GUI update and this method
0N/A * will return <tt>null</tt>.
0N/A *
0N/A * @return a <tt>SwingWorker</tt> to perform the GUI update; or
0N/A * <tt>null</tt>.
0N/A */
0N/A public abstract SwingWorker<?,?> newSwingWorker();
0N/A
0N/A /**
0N/A * Dispose this plugin. This method is called by JConsole to inform
0N/A * that this plugin will be discarded and that it should free
0N/A * any resources that it has allocated.
0N/A * The {@link #getContext JConsoleContext} can be in any
0N/A * {@link JConsoleContext#getConnectionState connection state} when
0N/A * this method is called.
0N/A */
0N/A public void dispose() {
0N/A // Default nop implementation
0N/A }
0N/A
0N/A /**
0N/A * Adds a {@link PropertyChangeListener PropertyChangeListener}
0N/A * to the {@link #getContext JConsoleContext} object for this plugin.
0N/A * This method is a convenient method for this plugin to register
0N/A * a listener when the {@code JConsoleContext} object may or
0N/A * may not be available.
0N/A *
0N/A * <p>For example, a plugin constructor can
0N/A * call this method to register a listener to listen to the
0N/A * {@link JConsoleContext.ConnectionState connectionState}
0N/A * property changes and the listener will be added to the
0N/A * {@link JConsoleContext#addPropertyChangeListener JConsoleContext}
0N/A * object when it is available.
0N/A *
0N/A * @param listener The {@code PropertyChangeListener} to be added
0N/A *
0N/A * @throws NullPointerException if {@code listener} is {@code null}.
0N/A */
0N/A public final void addContextPropertyChangeListener(PropertyChangeListener listener) {
0N/A if (listener == null) {
0N/A throw new NullPointerException("listener is null");
0N/A }
0N/A
0N/A if (context == null) {
0N/A // defer registration of the listener until setContext() is called
0N/A synchronized (this) {
0N/A // check again if context is not set
0N/A if (context == null) {
0N/A // maintain a listener list to be added later
0N/A if (listeners == null) {
0N/A listeners = new ArrayList<PropertyChangeListener>();
0N/A }
0N/A listeners.add(listener);
0N/A return;
0N/A }
0N/A }
0N/A }
0N/A context.addPropertyChangeListener(listener);
0N/A }
0N/A
0N/A /**
0N/A * Removes a {@link PropertyChangeListener PropertyChangeListener}
0N/A * from the listener list of the {@link #getContext JConsoleContext}
0N/A * object for this plugin.
0N/A * If {@code listener} was never added, no exception is
0N/A * thrown and no action is taken.
0N/A *
0N/A * @param listener the {@code PropertyChangeListener} to be removed
0N/A *
0N/A * @throws NullPointerException if {@code listener} is {@code null}.
0N/A */
0N/A public final void removeContextPropertyChangeListener(PropertyChangeListener listener) {
0N/A if (listener == null) {
0N/A throw new NullPointerException("listener is null");
0N/A }
0N/A
0N/A if (context == null) {
0N/A // defer registration of the listener until setContext() is called
0N/A synchronized (this) {
0N/A // check again if context is not set
0N/A if (context == null) {
0N/A if (listeners != null) {
0N/A listeners.remove(listener);
0N/A }
0N/A return;
0N/A }
0N/A }
0N/A }
0N/A context.removePropertyChangeListener(listener);
0N/A }
0N/A}