net.jmesnil.jmx.ui.internal.views.explorer.MBeanExplorer.java Source code

Java tutorial

Introduction

Here is the source code for net.jmesnil.jmx.ui.internal.views.explorer.MBeanExplorer.java

Source

/*******************************************************************************
 * Copyright (c) 2006 Jeff Mesnil
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 *  Code was inspired by org.eclipse.equinox.client source, (c) 2006 IBM 
 *******************************************************************************/

package net.jmesnil.jmx.ui.internal.views.explorer;

import javax.management.MBeanServerConnection;
import javax.management.MBeanServerNotification;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;

import net.jmesnil.jmx.resources.MBeanFeatureInfoWrapper;
import net.jmesnil.jmx.resources.MBeanInfoWrapper;
import net.jmesnil.jmx.ui.JMXUIActivator;
import net.jmesnil.jmx.ui.internal.EditorUtils;
import net.jmesnil.jmx.ui.internal.JMXImages;
import net.jmesnil.jmx.ui.internal.Messages;
import net.jmesnil.jmx.ui.internal.actions.MBeanServerConnectAction;
import net.jmesnil.jmx.ui.internal.actions.MBeanServerDisconnectAction;
import net.jmesnil.jmx.ui.internal.editors.MBeanEditorInput;
import net.jmesnil.jmx.ui.internal.tree.Node;
import net.jmesnil.jmx.ui.internal.tree.NodeUtils;
import net.jmesnil.jmx.ui.internal.tree.ObjectNameNode;
import net.jmesnil.jmx.ui.internal.tree.PropertyNode;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.ui.part.ISetSelectionTarget;
import org.eclipse.ui.part.ViewPart;

public class MBeanExplorer extends ViewPart implements ISetSelectionTarget {

    public static final String ID = "net.jmesnil.jmx.ui.internal.views.explorer.MBeanExplorer"; //$NON-NLS-1$

    private static final int HIERARCHICAL_LAYOUT = 0x1;
    private static final int FLAT_LAYOUT = 0x2;

    private static final String TAG_LAYOUT = "layout"; //$NON-NLS-1$
    private static final String TAG_LINKED_WITH_EDITOR = "linkedWithEditor"; //$NON-NLS-1$

    private TreeViewer viewer;

    private boolean currentLayoutIsFlat = false;
    private boolean linkingIsEnabled = false;

    private Action collapseAllAction;

    private Action connectAction;

    private Action disconnectAction;

    private LayoutActionGroup layoutActionGroup;

    private Action linkWithEditorAction;

    private NotificationListener registrationListener;

    private final ISelectionChangedListener postSelectionListener;

    private MBeanExplorerContentProvider contentProvider;

    private MBeanExplorerLabelProvider labelProvider;

    private final class NodePatternFilter extends PatternFilter {

        public NodePatternFilter() {
            super();
            setIncludeLeadingWildcard(true);
        }

        @Override
        protected boolean isLeafMatch(Viewer viewer, Object element) {
            if (element instanceof PropertyNode) {
                PropertyNode propNode = (PropertyNode) element;
                return wordMatches(propNode.getKey() + "=" //$NON-NLS-1$
                        + propNode.getValue());
            }
            return super.isLeafMatch(viewer, element);
        }

        @Override
        public boolean isElementVisible(Viewer viewer, Object element) {
            if (element instanceof Node) {
                return matchesObjectName((Node) element);
            }
            return false;
        }

        private boolean matchesObjectName(Node node) {
            if (node instanceof ObjectNameNode) {
                ObjectNameNode onNode = (ObjectNameNode) node;
                return wordMatches(onNode.getObjectName().toString());
            }
            boolean hasMatchingChildren = false;
            Node[] children = node.getChildren();
            for (int i = 0; i < children.length; i++) {
                Node child = children[i];
                hasMatchingChildren |= matchesObjectName(child);
            }
            return hasMatchingChildren;
        }
    }

    private final class CollapseAllAction extends Action {

        public CollapseAllAction() {
            setText(Messages.CollapseAllAction_text);
            JMXImages.setLocalImageDescriptors(this, "collapseall.gif"); //$NON-NLS-1$
        }

        @Override
        public void run() {
            viewer.collapseAll();
        }
    }

    private final IPartListener2 linkWithEditorListener = new IPartListener2() {
        public void partVisible(IWorkbenchPartReference partRef) {
        }

        public void partBroughtToTop(IWorkbenchPartReference partRef) {
        }

        public void partClosed(IWorkbenchPartReference partRef) {
        }

        public void partDeactivated(IWorkbenchPartReference partRef) {
        }

        public void partHidden(IWorkbenchPartReference partRef) {
        }

        public void partOpened(IWorkbenchPartReference partRef) {
        }

        public void partInputChanged(IWorkbenchPartReference partRef) {
            if (partRef instanceof IEditorReference) {
                editorActivated(((IEditorReference) partRef).getEditor(true));
            }
        }

        public void partActivated(IWorkbenchPartReference partRef) {
            if (partRef instanceof IEditorReference) {
                editorActivated(((IEditorReference) partRef).getEditor(true));
            }
        }
    };

    public MBeanExplorer() {
        postSelectionListener = new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                handlePostSelectionChanged(event);
            }
        };
    }

    @Override
    public void init(IViewSite site, IMemento memento) throws PartInitException {
        super.init(site, memento);
        restoreLayoutState(memento);
        restoreLinkWithEditorState(memento);
    }

    @Override
    public void saveState(IMemento memento) {
        saveLinkWithEditorState(memento);
        saveLayoutState(memento);
    }

    @Override
    public void createPartControl(Composite parent) {
        makeActions();
        fillActionBars();
        PatternFilter patternFilter = new NodePatternFilter();
        patternFilter.setIncludeLeadingWildcard(true);

        final FilteredTree filter = new FilteredTree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL,
                patternFilter);

        viewer = filter.getViewer();
        contentProvider = new MBeanExplorerContentProvider();
        contentProvider.setFlatLayout(currentLayoutIsFlat);
        viewer.setContentProvider(contentProvider);
        labelProvider = new MBeanExplorerLabelProvider();
        labelProvider.setFlatLayout(currentLayoutIsFlat);
        viewer.setLabelProvider(labelProvider);

        viewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                ISelection selection = event.getSelection();
                StructuredSelection structured = (StructuredSelection) selection;
                Object element = structured.getFirstElement();
                IEditorInput editorInput = EditorUtils.getEditorInput(element);
                if (editorInput != null) {
                    IEditorPart editor = EditorUtils.openMBeanEditor(editorInput);
                    if (editor != null) {
                        EditorUtils.revealInEditor(editor, element);
                    }
                } else {
                    boolean expanded = viewer.getExpandedState(element);
                    if (expanded) {
                        viewer.collapseToLevel(element, 1);
                    } else {
                        viewer.expandToLevel(element, 1);
                    }
                }
            }
        });
        viewer.addPostSelectionChangedListener(postSelectionListener);
        // workaround for issue #19 (observed on linux/gtk only)
        viewer.getControl().addListener(SWT.FocusIn, new Listener() {
            public void handleEvent(Event event) {
                JMXUIActivator.getActivePage().activate(getSite().getPart());
            }
        });
        getViewSite().setSelectionProvider(viewer);
    }

    @Override
    public void dispose() {
        removeRegistrationListener();
        // always remove even if we didn't register
        getSite().getPage().removePartListener(linkWithEditorListener);
        super.dispose();
    }

    private void makeActions() {
        collapseAllAction = new CollapseAllAction();
        connectAction = new MBeanServerConnectAction(this);
        disconnectAction = new MBeanServerDisconnectAction(this);
        layoutActionGroup = new LayoutActionGroup(this);
        layoutActionGroup.setFlatLayout(currentLayoutIsFlat);
        linkWithEditorAction = new Action(Messages.MBeanExplorer_linkWithEditorActionText, Action.AS_CHECK_BOX) {
            @Override
            public void run() {
                setLinkingEnabled(linkWithEditorAction.isChecked());
            }
        };
        JMXImages.setLocalImageDescriptors(linkWithEditorAction, "synced.gif"); //$NON-NLS-1$
        linkWithEditorAction.setChecked(linkingIsEnabled);
        linkWithEditorAction.run();
    }

    private void fillActionBars() {
        IActionBars actionBars = getViewSite().getActionBars();
        IMenuManager viewMenu = actionBars.getMenuManager();

        viewMenu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
        viewMenu.add(connectAction);
        viewMenu.add(disconnectAction);
        viewMenu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS + "-end"));//$NON-NLS-1$        

        layoutActionGroup.fillActionBars(actionBars);
        viewMenu.add(new Separator());
        viewMenu.add(linkWithEditorAction);

        actionBars.getToolBarManager().add(connectAction);
        actionBars.getToolBarManager().add(new Separator());
        actionBars.getToolBarManager().add(collapseAllAction);
        actionBars.getToolBarManager().add(linkWithEditorAction);
    }

    @SuppressWarnings("unchecked") //$NON-NLS-1$
    public void setMBeanServerConnection(MBeanServerConnection mbsc) {
        if (mbsc == null) {
            removeRegistrationListener();
            mbsc = null;
            viewer.setInput(null);
            return;
        }
        addRegistrationListener(mbsc);
        try {
            Node root = NodeUtils.createObjectNameTree(mbsc);
            viewer.setInput(root);
        } catch (Exception e) {
            JMXUIActivator.log(IStatus.ERROR, e.getMessage(), e);
        }
    }

    private void addRegistrationListener(MBeanServerConnection mbsc) {
        registrationListener = new NotificationListener() {
            public void handleNotification(Notification notifcation, Object handback) {
                if (notifcation instanceof MBeanServerNotification) {
                    try {
                        MBeanServerConnection mbsc = (MBeanServerConnection) handback;
                        final Node root = NodeUtils.createObjectNameTree(mbsc);
                        viewer.getControl().getDisplay().syncExec(new Runnable() {
                            public void run() {
                                viewer.setInput(root);
                            }
                        });
                    } catch (Exception e) {
                        JMXUIActivator.log(IStatus.ERROR, e.getMessage(), e);
                    }
                }
            }
        };
        try {
            ObjectName mbeanServerON = ObjectName.getInstance("JMImplementation:type=MBeanServerDelegate"); //$NON-NLS-1$
            mbsc.addNotificationListener(mbeanServerON, registrationListener, null, mbsc);
        } catch (Exception e) {
            JMXUIActivator.log(IStatus.ERROR, e.getMessage(), e);
        }
    }

    private void removeRegistrationListener() {
        MBeanServerConnection mbsc = JMXUIActivator.getDefault().getCurrentConnection();
        if (mbsc != null) {
            try {
                ObjectName mbeanServerON = ObjectName.getInstance("JMImplementation:type=MBeanServerDelegate"); //$NON-NLS-1$
                mbsc.removeNotificationListener(mbeanServerON, registrationListener);
            } catch (Exception e) {
                JMXUIActivator.log(IStatus.ERROR, e.getMessage(), e);
            }
        }
    }

    /**
     * Passing the focus request to the viewer's control.
     */
    @Override
    public void setFocus() {
        viewer.getControl().setFocus();
    }

    void toggleLayout() {
        currentLayoutIsFlat = !currentLayoutIsFlat;
        saveLayoutState(null);
        contentProvider.setFlatLayout(currentLayoutIsFlat);
        labelProvider.setFlatLayout(currentLayoutIsFlat);
        viewer.getControl().setRedraw(false);
        try {
            viewer.refresh();
        } finally {
            viewer.getControl().setRedraw(true);
        }
    }

    private void saveLayoutState(IMemento memento) {
        if (memento != null) {
            memento.putInteger(TAG_LAYOUT, getLayoutAsInt());
        } else {
            //if memento is null save in preference store
            IPreferenceStore store = JMXUIActivator.getDefault().getPreferenceStore();
            store.setValue(TAG_LAYOUT, getLayoutAsInt());
        }
    }

    private void restoreLayoutState(IMemento memento) {
        Integer state = null;
        if (memento != null)
            state = memento.getInteger(TAG_LAYOUT);

        // If no memento try an restore from preference store
        if (state == null) {
            IPreferenceStore store = JMXUIActivator.getDefault().getPreferenceStore();
            state = new Integer(store.getInt(TAG_LAYOUT));
        }

        if (state.intValue() == FLAT_LAYOUT)
            currentLayoutIsFlat = true;
        else if (state.intValue() == HIERARCHICAL_LAYOUT)
            currentLayoutIsFlat = false;
        else
            currentLayoutIsFlat = false;
    }

    private int getLayoutAsInt() {
        if (currentLayoutIsFlat)
            return FLAT_LAYOUT;
        else
            return HIERARCHICAL_LAYOUT;
    }

    boolean isCurrentLayoutFlat() {
        return currentLayoutIsFlat;
    }

    private boolean isLinkingEnabled() {
        return linkingIsEnabled;
    }

    private void setLinkingEnabled(boolean enabled) {
        linkingIsEnabled = enabled;
        saveLinkWithEditorState(null);
        IWorkbenchPage page = getSite().getPage();
        if (enabled) {
            page.addPartListener(linkWithEditorListener);

            IEditorPart editor = page.getActiveEditor();
            if (editor != null) {
                editorActivated(editor);
            }
        } else {
            page.removePartListener(linkWithEditorListener);
        }
    }

    private void saveLinkWithEditorState(IMemento memento) {
        int linkingIsEnabledAsInt = linkingIsEnabled ? 0 : 1;
        if (memento != null) {
            memento.putInteger(TAG_LINKED_WITH_EDITOR, linkingIsEnabledAsInt);
        } else {
            // if memento is null save in preference store
            IPreferenceStore store = JMXUIActivator.getDefault().getPreferenceStore();
            store.setValue(TAG_LINKED_WITH_EDITOR, linkingIsEnabledAsInt);
        }
    }

    private void restoreLinkWithEditorState(IMemento memento) {
        Integer state = null;
        if (memento != null)
            state = memento.getInteger(TAG_LINKED_WITH_EDITOR);

        // If no memento try an restore from preference store
        if (state == null) {
            IPreferenceStore store = JMXUIActivator.getDefault().getPreferenceStore();
            state = new Integer(store.getInt(TAG_LINKED_WITH_EDITOR));
        }

        if (state.intValue() == 0)
            linkingIsEnabled = true;
        else if (state.intValue() == 1)
            linkingIsEnabled = false;
        else
            linkingIsEnabled = false;
    }

    private void editorActivated(IEditorPart editor) {
        Object input = editor.getEditorInput();
        if (input == null || !(input instanceof MBeanEditorInput)) {
            return;
        }
        MBeanEditorInput mbeanInput = (MBeanEditorInput) input;
        if (!inputIsSelected(mbeanInput)) {
            showInput(mbeanInput);
        } else {
            viewer.getTree().showSelection();
        }
    }

    private boolean inputIsSelected(MBeanEditorInput input) {
        IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
        if (selection.size() != 1)
            return false;
        boolean inputIsSelected = input.equals(EditorUtils.getEditorInput(selection.getFirstElement()));
        return inputIsSelected;
    }

    private boolean showInput(MBeanEditorInput input) {
        MBeanInfoWrapper infoWrapper = input.getWrapper();
        ObjectName objectName = infoWrapper.getObjectName();
        Node root = (Node) viewer.getInput();
        if (root == null) {
            return false;
        }
        ObjectNameNode node = NodeUtils.findObjectNameNode(root, objectName);
        if (node == null) {
            return false;
        } else {
            ISelection newSelection = new StructuredSelection(node);
            if (viewer.getSelection().equals(newSelection)) {
                viewer.reveal(node);
            } else {
                viewer.setSelection(newSelection, true);
            }
            return true;
        }
    }

    private void handlePostSelectionChanged(SelectionChangedEvent event) {
        ISelection selection = event.getSelection();
        if (isLinkingEnabled()) {
            linkToEditor((IStructuredSelection) selection);
        }
    }

    private void linkToEditor(IStructuredSelection selection) {
        if (!isActivePart())
            return;
        Object obj = selection.getFirstElement();

        if (selection.size() == 1) {
            IEditorPart part = EditorUtils.isOpenInEditor(obj);
            if (part != null) {
                IWorkbenchPage page = getSite().getPage();
                page.bringToTop(part);
                if (obj instanceof MBeanFeatureInfoWrapper) {
                    EditorUtils.revealInEditor(part, obj);
                }
            }
        }
    }

    private boolean isActivePart() {
        return this == getSite().getPage().getActivePart();
    }

    public void selectReveal(ISelection selection) {
        if (isLinkingEnabled()) {
            viewer.setSelection(selection, true);
        }
    }
}