/******************************************************************************* * 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); } } }