summaryrefslogtreecommitdiff
path: root/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java')
-rw-r--r--qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java1372
1 files changed, 1372 insertions, 0 deletions
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java
new file mode 100644
index 0000000000..417734e5fb
--- /dev/null
+++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java
@@ -0,0 +1,1372 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.ui.views;
+
+import static org.apache.qpid.management.ui.Constants.*;
+import static org.apache.qpid.management.ui.ApplicationRegistry.DATA_DIR;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.qpid.management.common.mbeans.ConfigurationManagement;
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.apache.qpid.management.common.mbeans.ServerInformation;
+import org.apache.qpid.management.common.mbeans.UserManagement;
+import org.apache.qpid.management.ui.ApiVersion;
+import org.apache.qpid.management.ui.ApplicationRegistry;
+import org.apache.qpid.management.ui.ManagedBean;
+import org.apache.qpid.management.ui.ManagedObject;
+import org.apache.qpid.management.ui.ManagedServer;
+import org.apache.qpid.management.ui.ServerRegistry;
+import org.apache.qpid.management.ui.exceptions.InfoRequiredException;
+import org.apache.qpid.management.ui.exceptions.ManagementConsoleException;
+import org.apache.qpid.management.ui.jmx.JMXServerRegistry;
+import org.apache.qpid.management.ui.jmx.MBeanUtility;
+import org.eclipse.jface.preference.PreferenceStore;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.IFontProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ITreeViewerListener;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeExpansionEvent;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * Navigation View for navigating the managed servers and managed beans on
+ * those servers
+ * @author Bhupendra Bhardwaj
+ */
+public class NavigationView extends ViewPart
+{
+ public static final String ID = "org.apache.qpid.management.ui.navigationView";
+ public static final String INI_FILENAME = DATA_DIR + File.separator + "qpidmc_navigation.ini";
+
+ private static final String INI_SERVERS = "Servers";
+ private static final String INI_QUEUES = QUEUE + "s";
+ private static final String INI_CONNECTIONS = CONNECTION + "s";
+ private static final String INI_EXCHANGES = EXCHANGE + "s";
+
+ private TreeViewer _treeViewer = null;
+ private TreeObject _serversRootNode = null;
+
+ private PreferenceStore _preferences;
+ // Map of connected servers
+ private ConcurrentHashMap<ManagedServer, TreeObject> _managedServerMap = new ConcurrentHashMap<ManagedServer, TreeObject>();
+
+ private static HashSet<String> _serverTopLevelMBeans = new HashSet<String>();
+ {
+ _serverTopLevelMBeans.add(UserManagement.TYPE);
+ _serverTopLevelMBeans.add(LoggingManagement.TYPE);
+ _serverTopLevelMBeans.add(ConfigurationManagement.TYPE);
+ _serverTopLevelMBeans.add(ServerInformation.TYPE);
+ }
+
+ private void createTreeViewer(Composite parent)
+ {
+ _treeViewer = new TreeViewer(parent);
+ _treeViewer.setContentProvider(new ContentProviderImpl());
+ _treeViewer.setLabelProvider(new LabelProviderImpl());
+ _treeViewer.setSorter(new ViewerSorterImpl());
+
+ // layout the tree viewer below the label field, to cover the area
+ GridData layoutData = new GridData();
+ layoutData.grabExcessHorizontalSpace = true;
+ layoutData.grabExcessVerticalSpace = true;
+ layoutData.horizontalAlignment = GridData.FILL;
+ layoutData.verticalAlignment = GridData.FILL;
+ _treeViewer.getControl().setLayoutData(layoutData);
+ _treeViewer.setUseHashlookup(true);
+
+ createListeners();
+ }
+
+ /**
+ * Creates listeners for the JFace treeviewer
+ */
+ private void createListeners()
+ {
+ _treeViewer.addDoubleClickListener(new IDoubleClickListener()
+ {
+ public void doubleClick(DoubleClickEvent event)
+ {
+ IStructuredSelection ss = (IStructuredSelection) event.getSelection();
+ if ((ss == null) || (ss.getFirstElement() == null))
+ {
+ return;
+ }
+
+ boolean state = _treeViewer.getExpandedState(ss.getFirstElement());
+ _treeViewer.setExpandedState(ss.getFirstElement(), !state);
+ }
+ });
+
+ _treeViewer.addTreeListener(new ITreeViewerListener()
+ {
+ public void treeExpanded(TreeExpansionEvent event)
+ {
+ getSite().getShell().getDisplay().asyncExec(
+ new Runnable()
+ {
+ public void run()
+ {
+ _treeViewer.refresh();
+ }
+ });
+ }
+
+ public void treeCollapsed(TreeExpansionEvent event)
+ {
+ getSite().getShell().getDisplay().asyncExec(
+ new Runnable()
+ {
+ public void run()
+ {
+ _treeViewer.refresh();
+ }
+ });
+ }
+ });
+
+ // This listener is for popup menu, which pops up if a queue,exchange or connection is selected
+ // with right click.
+ _treeViewer.getTree().addListener(SWT.MenuDetect, new Listener()
+ {
+ Display display = getSite().getShell().getDisplay();
+ final Shell shell = new Shell(display);
+
+ public void handleEvent(Event event)
+ {
+ Tree widget = (Tree) event.widget;
+ TreeItem[] items = widget.getSelection();
+ if (items == null)
+ {
+ return;
+ }
+
+ // Get the selected node
+ final TreeObject selectedNode = (TreeObject) items[0].getData();
+ final TreeObject parentNode = selectedNode.getParent();
+
+ // This popup is only for mbeans and only connection,exchange and queue types
+ if ((parentNode == null) || !MBEAN.equals(selectedNode.getType())
+ || !(CONNECTION.equals(parentNode.getName()) || QUEUE.equals(parentNode.getName())
+ || EXCHANGE.equals(parentNode.getName())))
+ {
+ return;
+ }
+
+ Menu menu = new Menu(shell, SWT.POP_UP);
+ MenuItem item = new MenuItem(menu, SWT.PUSH);
+ // Add the action item, which will remove the node from the tree if selected
+ item.setText(ACTION_REMOVE_MBEANNODE);
+ item.addListener(SWT.Selection, new Listener()
+ {
+ public void handleEvent(Event e)
+ {
+ removeManagedObject(parentNode, (ManagedBean) selectedNode.getManagedObject(), true);
+ _treeViewer.refresh();
+ // set the selection to the parent node
+ _treeViewer.setSelection(new StructuredSelection(parentNode));
+ }
+ });
+ menu.setLocation(event.x, event.y);
+ menu.setVisible(true);
+ while (!menu.isDisposed() && menu.isVisible())
+ {
+ if (!display.readAndDispatch())
+ {
+ display.sleep();
+ }
+ }
+
+ menu.dispose();
+ }
+ });
+ }
+
+ /**
+ * Creates Qpid Server connection
+ * @param server
+ * @throws Exception
+ */
+ private void createJMXServerConnection(ManagedServer server) throws Exception
+ {
+ // Currently Qpid Management Console only supports JMX MBeanServer
+ JMXServerRegistry serverRegistry = new JMXServerRegistry(server);
+
+ try
+ {
+ //determine the management API version of the server just connected to
+ MBeanUtility.classifyManagementApiVersion(server, serverRegistry);
+ }
+ catch (Exception e)
+ {
+ //Exception classifying the server API, clean up the connection and rethrow
+ serverRegistry.closeServerConnection();
+ throw e;
+ }
+
+ //check that the console supports the API major version encountered, otherwise abort.
+ ApiVersion serverAPI = serverRegistry.getManagementApiVersion();
+
+ int serverMajor = serverAPI.getMajor();
+ int supportedMajor = ApplicationRegistry.SUPPORTED_QPID_JMX_API_MAJOR_VERSION;
+
+ if(serverMajor > supportedMajor)
+ {
+ serverRegistry.closeServerConnection();
+ throw new ManagementConsoleException("The server management API version encountered is not supported"
+ + " by this console release. Please check for an updated console release.");
+ }
+
+ //connection succeeded, add the ServerRegistry to the ApplicationRegistry
+ ApplicationRegistry.addServer(server, serverRegistry);
+ }
+
+ /**
+ * Adds a new server node in the navigation view if server connection is successful.
+ * @param transportProtocol
+ * @param host
+ * @param port
+ * @param domain
+ * @throws Exception
+ */
+ public void addNewServer(String host, int port, String domain, String user, String pwd)
+ throws Exception
+ {
+ ManagedServer managedServer = new ManagedServer(host, port, domain, user, pwd);
+
+ String server = managedServer.getName();
+ List<TreeObject> list = _serversRootNode.getChildren();
+ for (TreeObject node : list)
+ {
+ ManagedServer nodeServer = (ManagedServer)node.getManagedObject();
+ if (server.equals(nodeServer.getName()))
+ {
+ // Server is already in the list of added servers, so now connect it.
+ // Set the server node as selected and then connect it.
+ _treeViewer.setSelection(new StructuredSelection(node));
+ reconnect(user, pwd);
+
+ return;
+ }
+ }
+
+ // The server is not in the list of already added servers, so now connect and add it.
+ createJMXServerConnection(managedServer);
+
+ // Server connection is successful. Now add the server in the tree
+ TreeObject serverNode = new TreeObject(server, NODE_TYPE_SERVER);
+ serverNode.setManagedObject(managedServer);
+ _serversRootNode.addChild(serverNode);
+
+ // Add server in the connected server map
+ _managedServerMap.put(managedServer, serverNode);
+
+ // populate the server tree
+ try
+ {
+ populateServer(serverNode);
+ }
+ catch (SecurityException ex)
+ {
+ disconnect(managedServer);
+ throw ex;
+ }
+
+ // Add the Queue/Exchanges/Connections from config file into the navigation tree
+ addConfiguredItems(managedServer);
+
+ _treeViewer.refresh();
+
+ expandInitialMBeanView(serverNode);
+
+ //(re)select the server node now that it is connected to force a selectionEvent
+ _treeViewer.setSelection(new StructuredSelection(serverNode));
+ _treeViewer.refresh();
+
+ // save server address in file
+ addServerInConfigFile(server);
+ }
+
+ /**
+ * Create the config file, if it doesn't already exist.
+ * Exits the application if the file could not be created.
+ */
+ private void createConfigFile()
+ {
+ File dir = new File(DATA_DIR);
+ if (!dir.exists())
+ {
+ if(!dir.mkdir())
+ {
+ System.out.println("Could not create application data directory " + DATA_DIR);
+ System.exit(1);
+ }
+ }
+
+ File file = new File(INI_FILENAME);
+ try
+ {
+ if (!file.exists())
+ {
+ file.createNewFile();
+ }
+ }
+ catch (IOException ex)
+ {
+ System.out.println("Could not write to the file " + INI_FILENAME);
+ System.out.println(ex);
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Server addresses are stored in a file. When user launches the application again, the
+ * server addresses are picked up from the file and shown in the navigfation view. This method
+ * adds the server address in a file, when a new server is added in the navigation view.
+ * @param serverAddress
+ */
+ private void addServerInConfigFile(String serverAddress)
+ {
+ // Check if the address already exists
+ List<String> list = getServerListFromFile();
+ if ((list != null) && list.contains(serverAddress))
+ {
+ return;
+ }
+
+ // Get the existing server list and add to that
+ String servers = _preferences.getString(INI_SERVERS);
+ String value = (servers.length() != 0) ? (servers + "," + serverAddress) : serverAddress;
+ _preferences.putValue(INI_SERVERS, value);
+ try
+ {
+ _preferences.save();
+ }
+ catch (IOException ex)
+ {
+ System.err.println("Could not add " + serverAddress + " in " + INI_SERVERS + " (" + INI_FILENAME + ")");
+ System.out.println(ex);
+ }
+ }
+
+ /**
+ * Adds the item (Queue/Exchange/Connection) to the config file
+ * @param server
+ * @param virtualhost
+ * @param type - (Queue or Exchange or Connection)
+ * @param name - item name
+ */
+ private void addItemInConfigFile(TreeObject node)
+ {
+ ManagedBean mbean = (ManagedBean) node.getManagedObject();
+ String server = mbean.getServer().getName();
+ String virtualhost = mbean.getVirtualHostName();
+ String type = node.getParent().getName() + "s";
+ String name = node.getName();
+ String itemKey = server + "." + virtualhost + "." + type;
+
+ // Check if the item already exists in the config file
+ List<String> list = getConfiguredItemsFromFile(itemKey);
+ if ((list != null) && list.contains(name))
+ {
+ return;
+ }
+
+ // Add this item to the existing list of items
+ String items = _preferences.getString(itemKey);
+ String value = (items.length() != 0) ? (items + "," + name) : name;
+ _preferences.putValue(itemKey, value);
+ try
+ {
+ _preferences.save();
+ }
+ catch (IOException ex)
+ {
+ System.err.println("Could not add " + name + " in " + itemKey + " (" + INI_FILENAME + ")");
+ System.out.println(ex);
+ }
+ }
+
+ private void removeItemFromConfigFile(TreeObject node)
+ {
+ ManagedBean mbean = (ManagedBean) node.getManagedObject();
+ String server = mbean.getServer().getName();
+ String vHost = mbean.getVirtualHostName();
+ String type = node.getParent().getName() + "s";
+ String itemKey = server + "." + vHost + "." + type;
+
+ List<String> list = getConfiguredItemsFromFile(itemKey);
+ if (list.contains(node.getName()))
+ {
+ list.remove(node.getName());
+ String value = "";
+ for (String item : list)
+ {
+ value += item + ",";
+ }
+
+ value = (value.lastIndexOf(",") != -1) ? value.substring(0, value.lastIndexOf(",")) : value;
+
+ _preferences.putValue(itemKey, value);
+ try
+ {
+ _preferences.save();
+ }
+ catch (IOException ex)
+ {
+ System.err.println("Error in updating the config file " + INI_FILENAME);
+ System.out.println(ex);
+ }
+ }
+ }
+
+ //check if the MBeanInfo can be retrieved.
+ private boolean haveAccessPermission(ManagedBean mbean)
+ {
+ try
+ {
+ MBeanUtility.getMBeanInfo(mbean);
+ }
+ catch(Exception ex)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Queries the qpid server for MBeans and populates the navigation view with all MBeans for
+ * the given server node.
+ * @param serverNode
+ * @throws Exception
+ */
+ private void populateServer(TreeObject serverNode) throws Exception
+ {
+ ManagedServer server = (ManagedServer) serverNode.getManagedObject();
+ String domain = server.getDomain();
+
+ List<ManagedBean> mbeans = MBeanUtility.getManagedObjectsForDomain(server, domain);
+ for (ManagedBean mbean : mbeans)
+ {
+ mbean.setServer(server);
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(server);
+ serverRegistry.addManagedObject(mbean);
+
+ // Add all mbeans other than Connections, Exchanges and Queues. Because these will be added
+ // manually by selecting from MBeanView
+ if (!(mbean.isConnection() || mbean.isExchange() || mbean.isQueue()))
+ {
+ //if we cant get the MBeanInfo then we cant display the mbean, so dont add it to the tree
+ if (haveAccessPermission(mbean))
+ {
+ addManagedBean(serverNode, mbean);
+ }
+ }
+ }
+ // To make it work with the broker without virtual host implementation.
+ // This will add the default nodes to the domain node
+ boolean hasVirtualHost = false;
+ for (TreeObject child : serverNode.getChildren())
+ {
+ if (child.getName().startsWith(VIRTUAL_HOST))
+ {
+ hasVirtualHost = true;
+ break;
+ }
+ }
+
+ if (!hasVirtualHost){
+ addDefaultNodes(serverNode);
+ }
+ }
+
+ /**
+ * Add these three types - Connection, Exchange, Queue
+ * By adding these, these will always be available, even if there are no mbeans under thse types
+ * This is required because, the mbeans will be added from mbeanview, by selecting from the list
+ * @param parent Node
+ */
+ private void addDefaultNodes(TreeObject parent)
+ {
+ TreeObject typeChild = new TreeObject(CONNECTION, NODE_TYPE_MBEANTYPE);
+ typeChild.setParent(parent);
+ typeChild.setVirtualHost(parent.getVirtualHost());
+ typeChild = new TreeObject(EXCHANGE, NODE_TYPE_MBEANTYPE);
+ typeChild.setParent(parent);
+ typeChild.setVirtualHost(parent.getVirtualHost());
+ typeChild = new TreeObject(QUEUE, NODE_TYPE_MBEANTYPE);
+ typeChild.setParent(parent);
+ typeChild.setVirtualHost(parent.getVirtualHost());
+
+ // Add common notification node for virtual host
+ TreeObject notificationNode = new TreeObject(NOTIFICATIONS, NOTIFICATIONS);
+ notificationNode.setParent(parent);
+ notificationNode.setVirtualHost(parent.getVirtualHost());
+ }
+
+ /**
+ * Checks if a particular mbeantype is already there in the navigation view for a domain.
+ * This is used while populating domain with mbeans.
+ * @param parent
+ * @param typeName
+ * @return Node if given mbeantype already exists, otherwise null
+ */
+ private TreeObject getMBeanTypeNode(TreeObject parent, String typeName)
+ {
+ List<TreeObject> childNodes = parent.getChildren();
+ for (TreeObject child : childNodes)
+ {
+ if ((NODE_TYPE_MBEANTYPE.equals(child.getType()) || NODE_TYPE_TYPEINSTANCE.equals(child.getType()))
+ && typeName.equals(child.getName()))
+ {
+ return child;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean doesMBeanNodeAlreadyExist(TreeObject typeNode, String mbeanName)
+ {
+ List<TreeObject> childNodes = typeNode.getChildren();
+ for (TreeObject child : childNodes)
+ {
+ if (MBEAN.equals(child.getType()) && mbeanName.equals(child.getName()))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Adds the given MBean to the given domain node.
+ * sample ObjectNames -
+ * org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=localhost
+ * org.apache.qpid:type=VirtualHost.Queue,VirtualHost=test,name=ping_1
+ * @param parent parent tree node to add the mbean to
+ * @param mbean mbean to add
+ */
+ private void addManagedBean(TreeObject parent, ManagedBean mbean)
+ {
+ String name = mbean.getName();
+ // Split the mbean type into array of Strings, to create hierarchy
+ // eg. type=VirtualHost.VirtualHostManager,VirtualHost=localhost will be:
+ // localhost->VirtualHostManager
+ // eg. type=org.apache.qpid:type=VirtualHost.Queue,VirtualHost=test,name=ping will be:
+ // test->Queue->ping
+ String[] types = mbean.getType().split("\\.");
+ TreeObject typeNode = null;
+ TreeObject parentNode = parent;
+
+ // Run this loop till all nodes(hierarchy) for this mbean are created. This loop only creates
+ // all the required parent nodes for the mbean
+ for (int i = 0; i < types.length; i++)
+ {
+ String type = types[i];
+
+ if(types.length == 1 && _serverTopLevelMBeans.contains(type))
+ {
+ //This mbean is not to be contained in a type hierarchy
+ //Just add it as a child of the server node.
+ break;
+ }
+
+ String valueOftype = mbean.getProperty(type);
+ // If value is not null, then there will be a parent node for this mbean
+ // eg. for type=VirtualHost the value is "test"
+ typeNode = getMBeanTypeNode(parentNode, type);
+
+ // create the type node if not already created
+ if (typeNode == null)
+ {
+ // If the ObjectName doesn't have name property, that means there will be only one instance
+ // of this mbean for given "type". So there will be no type node created for this mbean.
+ if ((name == null) && (i == (types.length - 1)))
+ {
+ break;
+ }
+
+ // create a node for "type"
+ typeNode = createTypeNode(parentNode, type);
+ if (!type.equals(VIRTUAL_HOST))
+ {
+ typeNode.setVirtualHost(mbean.getVirtualHostName());
+ }
+ }
+
+ // now type node create becomes the parent node for next node in hierarchy
+ parentNode = typeNode;
+
+ /*
+ * Now create instances node for this type if value exists.
+ */
+ if (valueOftype == null)
+ {
+ // No instance node will be created when value is null (eg type=Queue)
+ break;
+ }
+
+ // For different virtual hosts, the nodes with given value will be created.
+ // eg type=VirtualHost, value=test
+ typeNode = getMBeanTypeNode(parentNode, valueOftype);
+ if (typeNode == null)
+ {
+ typeNode = createTypeInstanceNode(parentNode, valueOftype);
+ typeNode.setVirtualHost(mbean.getVirtualHostName());
+
+ // Create default nodes for VHost instances
+ if (type.equals(VIRTUAL_HOST))
+ {
+ addDefaultNodes(typeNode);
+ }
+ }
+
+ parentNode = typeNode;
+ }
+
+ if (typeNode == null)
+ {
+ typeNode = parentNode;
+ }
+
+ // Check if an MBean is already added
+ if (doesMBeanNodeAlreadyExist(typeNode, name))
+ {
+ return;
+ }
+
+ // Add the mbean node now
+ TreeObject mbeanNode = new TreeObject(mbean);
+ mbeanNode.setVirtualHost(mbean.getVirtualHostName());
+ mbeanNode.setParent(typeNode);
+
+ // Add the mbean to the config file
+ if (mbean.isQueue() || mbean.isExchange() || mbean.isConnection())
+ {
+ addItemInConfigFile(mbeanNode);
+ }
+ }
+
+ private TreeObject createTypeNode(TreeObject parent, String name)
+ {
+ TreeObject typeNode = new TreeObject(name, NODE_TYPE_MBEANTYPE);
+ typeNode.setParent(parent);
+
+ return typeNode;
+ }
+
+ private TreeObject createTypeInstanceNode(TreeObject parent, String name)
+ {
+ TreeObject typeNode = new TreeObject(name, NODE_TYPE_TYPEINSTANCE);
+ typeNode.setParent(parent);
+
+ return typeNode;
+ }
+
+ /**
+ * Removes all the child nodes of the given parent node. Used when closing a server.
+ * @param parent
+ */
+ private void removeManagedObject(TreeObject parent)
+ {
+ if(parent == null)
+ {
+ return;
+ }
+
+ List<TreeObject> list = parent.getChildren();
+ for (TreeObject child : list)
+ {
+ removeManagedObject(child);
+ }
+
+ list.clear();
+ }
+
+ /**
+ * Removes the mbean from the tree
+ * @param parent
+ * @param mbean
+ */
+ private void removeManagedObject(TreeObject parent, ManagedBean mbean, boolean removeFromConfigFile)
+ {
+ List<TreeObject> list = parent.getChildren();
+ TreeObject objectToRemove = null;
+ for (TreeObject child : list)
+ {
+ if (MBEAN.equals(child.getType()))
+ {
+ String name = (mbean.getName() != null) ? mbean.getName() : mbean.getType();
+ if (child.getName().equals(name))
+ {
+ objectToRemove = child;
+
+ break;
+ }
+ }
+ else
+ {
+ removeManagedObject(child, mbean, removeFromConfigFile);
+ }
+ }
+
+ if (objectToRemove != null)
+ {
+ list.remove(objectToRemove);
+ if(removeFromConfigFile)
+ {
+ removeItemFromConfigFile(objectToRemove);
+ }
+ }
+
+ }
+
+ /**
+ * Closes the Qpid server connection
+ */
+ public void disconnect() throws Exception
+ {
+ TreeObject selectedNode = getSelectedServerNode();
+ ManagedServer managedServer = (ManagedServer) selectedNode.getManagedObject();
+ disconnect(managedServer);
+ }
+
+ private void disconnect(ManagedServer managedServer) throws Exception
+ {
+ if (!_managedServerMap.containsKey(managedServer))
+ {
+ return;
+ }
+
+ // Close server connection
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(managedServer);
+ if (serverRegistry == null) // server connection is already closed
+ {
+ return;
+ }
+
+ // Add server to the closed server list and the worker thread will remove the server from required places.
+ ApplicationRegistry.serverConnectionClosed(managedServer);
+
+ //close the connection
+ serverRegistry.closeServerConnection();
+ }
+
+ /**
+ * Connects the selected server node
+ * @throws Exception
+ */
+ public void reconnect(String user, String password) throws Exception
+ {
+ TreeObject selectedNode = getSelectedServerNode();
+ ManagedServer managedServer = (ManagedServer) selectedNode.getManagedObject();
+ if (_managedServerMap.containsKey(managedServer))
+ {
+ throw new InfoRequiredException("Server " + managedServer.getName() + " is already connected");
+ }
+
+ managedServer.setUser(user);
+ managedServer.setPassword(password);
+ createJMXServerConnection(managedServer);
+
+ // put the server in the managed server map
+ _managedServerMap.put(managedServer, selectedNode);
+
+ try
+ {
+ // populate the server tree now
+ populateServer(selectedNode);
+ }
+ catch (SecurityException ex)
+ {
+ disconnect(managedServer);
+ throw ex;
+ }
+
+
+ // Add the Queue/Exchanges/Connections from config file into the navigation tree
+ addConfiguredItems(managedServer);
+
+ expandInitialMBeanView(selectedNode);
+
+ //(re)select the server node now that it is connected to force a selectionEvent
+ _treeViewer.setSelection(new StructuredSelection(selectedNode));
+ _treeViewer.refresh();
+ }
+
+ private void expandInitialMBeanView(TreeObject serverNode)
+ {
+ if (serverNode.getChildren().size() == 0 )
+ {
+ return;
+ }
+ else
+ {
+ _treeViewer.setExpandedState(serverNode , true);
+ }
+
+ List<TreeObject> children = serverNode.getChildren();
+ for (TreeObject child : children)
+ {
+ if (child.getChildren().size() > 0)
+ {
+ _treeViewer.setExpandedState(child, true);
+ }
+ }
+ }
+
+ /**
+ * Adds the items(queues/exchanges/connectins) from config file to the server tree
+ * @param server
+ */
+ private void addConfiguredItems(ManagedServer server)
+ {
+ ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(server);
+ List<String> list = serverRegistry.getVirtualHosts();
+ for (String virtualHost : list)
+ {
+ // Add Queues
+ String itemKey = server.getName() + "." + virtualHost + "." + INI_QUEUES;
+ List<String> items = getConfiguredItemsFromFile(itemKey);
+ List<ManagedBean> mbeans = serverRegistry.getQueues(virtualHost);
+ addConfiguredItems(items, mbeans);
+
+ // Add Exchanges
+ itemKey = server.getName() + "." + virtualHost + "." + INI_EXCHANGES;
+ items = getConfiguredItemsFromFile(itemKey);
+ mbeans = serverRegistry.getExchanges(virtualHost);
+ addConfiguredItems(items, mbeans);
+
+ // Add Connections
+ itemKey = server.getName() + "." + virtualHost + "." + INI_CONNECTIONS;
+ items = getConfiguredItemsFromFile(itemKey);
+ mbeans = serverRegistry.getConnections(virtualHost);
+ addConfiguredItems(items, mbeans);
+ }
+ }
+
+ /**
+ * Gets the mbeans corresponding to the items and adds those to the navigation tree
+ * @param items
+ * @param mbeans
+ */
+ private void addConfiguredItems(List<String> items, List<ManagedBean> mbeans)
+ {
+ if ((items == null) || (items.isEmpty() || (mbeans == null)) || mbeans.isEmpty())
+ {
+ return;
+ }
+
+ for (String item : items)
+ {
+ for (ManagedBean mbean : mbeans)
+ {
+ if (item.equals(mbean.getName()))
+ {
+ addManagedBean(mbean);
+
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Closes the Qpid server connection if not already closed and removes the server node from the navigation view and
+ * also from the ini file stored in the system.
+ * @throws Exception
+ */
+ public void removeServer() throws Exception
+ {
+ disconnect();
+
+ // Remove from the Tree
+ String serverNodeName = getSelectedServerNode().getName();
+ List<TreeObject> list = _serversRootNode.getChildren();
+ TreeObject objectToRemove = null;
+ for (TreeObject child : list)
+ {
+ if (child.getName().equals(serverNodeName))
+ {
+ objectToRemove = child;
+
+ break;
+ }
+ }
+
+ if (objectToRemove != null)
+ {
+ list.remove(objectToRemove);
+ }
+
+ _treeViewer.refresh();
+
+ // Remove from the ini file
+ removeServerFromConfigFile(serverNodeName);
+ }
+
+ private void removeServerFromConfigFile(String serverNodeName)
+ {
+ List<String> serversList = getServerListFromFile();
+ serversList.remove(serverNodeName);
+
+ String value = "";
+ for (String item : serversList)
+ {
+ value += item + ",";
+ }
+
+ value = (value.lastIndexOf(",") != -1) ? value.substring(0, value.lastIndexOf(",")) : value;
+
+ _preferences.putValue(INI_SERVERS, value);
+
+ try
+ {
+ _preferences.save();
+ }
+ catch (IOException ex)
+ {
+ System.err.println("Error in updating the config file " + INI_FILENAME);
+ System.out.println(ex);
+ }
+ }
+
+ /**
+ * @return the server addresses from the ini file
+ * @throws Exception
+ */
+ private List<String> getServerListFromFile()
+ {
+ return getConfiguredItemsFromFile(INI_SERVERS);
+ }
+
+ /**
+ * Returns the list of items from the config file.
+ * sample ini file:
+ * Servers=localhost:8999,127.0.0.1:8999
+ * localhost.virtualhost1.Queues=queue1,queue2
+ * localhost.virtualhost1.Exchanges=exchange1,exchange2
+ * localhost.virtualhost2.Connections=conn1
+ * @param key
+ * @return
+ */
+ private List<String> getConfiguredItemsFromFile(String key)
+ {
+ List<String> list = new ArrayList<String>();
+ String items = _preferences.getString(key);
+ if (items.length() != 0)
+ {
+ String[] array = items.split(",");
+ for (String item : array)
+ {
+ list.add(item);
+ }
+ }
+
+ return list;
+ }
+
+ public TreeObject getSelectedServerNode() throws Exception
+ {
+ IStructuredSelection ss = (IStructuredSelection) _treeViewer.getSelection();
+ TreeObject selectedNode = (TreeObject) ss.getFirstElement();
+ if (ss.isEmpty() || (selectedNode == null) || (!selectedNode.getType().equals(NODE_TYPE_SERVER)))
+ {
+ throw new InfoRequiredException("Please select the server");
+ }
+
+ return selectedNode;
+ }
+
+ /**
+ * This is a callback that will allow us to create the viewer and initialize
+ * it.
+ */
+ public void createPartControl(Composite parent)
+ {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginHeight = 2;
+ gridLayout.marginWidth = 2;
+ gridLayout.horizontalSpacing = 0;
+ gridLayout.verticalSpacing = 2;
+ composite.setLayout(gridLayout);
+
+ createTreeViewer(composite);
+ _serversRootNode = new TreeObject(NAVIGATION_ROOT, "ROOT");
+
+ _treeViewer.setInput(_serversRootNode);
+ // set viewer as selection event provider for MBeanView
+ getSite().setSelectionProvider(_treeViewer);
+
+ // Start worker thread to refresh tree for added or removed objects
+ (new Thread(new Worker())).start();
+
+ createConfigFile();
+ _preferences = new PreferenceStore(INI_FILENAME);
+
+ try
+ {
+ _preferences.load();
+ }
+ catch (IOException ex)
+ {
+ System.out.println(ex);
+ }
+
+ // load the list of servers already added from file
+ List<String> serversList = getServerListFromFile();
+ if (serversList != null)
+ {
+ for (String serverAddress : serversList)
+ {
+ String[] server = serverAddress.split(":");
+ ManagedServer managedServer = new ManagedServer(server[0], Integer.parseInt(server[1]), "org.apache.qpid");
+ TreeObject serverNode = new TreeObject(serverAddress, NODE_TYPE_SERVER);
+ serverNode.setManagedObject(managedServer);
+ _serversRootNode.addChild(serverNode);
+ }
+ }
+
+ _treeViewer.refresh();
+
+ }
+
+ /**
+ * Passing the focus request to the viewer's control.
+ */
+ public void setFocus()
+ { }
+
+ public void refresh()
+ {
+ _treeViewer.refresh();
+ }
+
+ /**
+ * Content provider class for the tree viewer
+ */
+ private static class ContentProviderImpl implements ITreeContentProvider
+ {
+ public Object[] getElements(Object parent)
+ {
+ return getChildren(parent);
+ }
+
+ public Object[] getChildren(final Object parentElement)
+ {
+ final TreeObject node = (TreeObject) parentElement;
+
+ return node.getChildren().toArray(new TreeObject[0]);
+ }
+
+ public Object getParent(final Object element)
+ {
+ final TreeObject node = (TreeObject) element;
+
+ return node.getParent();
+ }
+
+ public boolean hasChildren(final Object element)
+ {
+ final TreeObject node = (TreeObject) element;
+
+ return !node.getChildren().isEmpty();
+ }
+
+ public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput)
+ {
+ // Do nothing
+ }
+
+ public void dispose()
+ {
+ // Do nothing
+ }
+ }
+
+ /**
+ * Label provider class for the tree viewer
+ */
+ private class LabelProviderImpl extends LabelProvider implements IFontProvider
+ {
+ public Image getImage(Object element)
+ {
+ TreeObject node = (TreeObject) element;
+ if (node.getType().equals(NOTIFICATIONS))
+ {
+ return ApplicationRegistry.getImage(NOTIFICATION_IMAGE);
+ }
+ else if (!node.getType().equals(MBEAN))
+ {
+ if (_treeViewer.getExpandedState(node))
+ {
+ return ApplicationRegistry.getImage(OPEN_FOLDER_IMAGE);
+ }
+ else
+ {
+ return ApplicationRegistry.getImage(CLOSED_FOLDER_IMAGE);
+ }
+
+ }
+ else
+ {
+ ManagedObject obj = node.getManagedObject();
+ if(obj instanceof ManagedBean)
+ {
+ ManagedBean mbean = (ManagedBean) obj;
+ String mbeanType = mbean.getType();
+
+ if(mbeanType.equals(LoggingManagement.TYPE))
+ {
+ return ApplicationRegistry.getImage(LOGGING_MANAGEMENT_IMAGE);
+ }
+ else if(mbeanType.equals(UserManagement.TYPE))
+ {
+ return ApplicationRegistry.getImage(USER_MANAGEMENT_IMAGE);
+ }
+ else if(mbeanType.equals(ConfigurationManagement.TYPE))
+ {
+ return ApplicationRegistry.getImage(CONFIGURATION_MANAGEMENT_IMAGE);
+ }
+ else if(mbeanType.equals(ServerInformation.TYPE))
+ {
+ return ApplicationRegistry.getImage(SERVER_INFO_IMAGE);
+ }
+ else if(mbeanType.equals("VirtualHost.VirtualHostManager"))
+ {
+ return ApplicationRegistry.getImage(VHOST_MANAGER_IMAGE);
+ }
+ else
+ {
+ return ApplicationRegistry.getImage(MBEAN_IMAGE);
+ }
+
+ }
+ else
+ {
+ return ApplicationRegistry.getImage(MBEAN_IMAGE);
+ }
+ }
+ }
+
+ public String getText(Object element)
+ {
+ TreeObject node = (TreeObject) element;
+ if (node.getType().equals(NODE_TYPE_MBEANTYPE))
+ {
+ return node.getName() + "s";
+ }
+ else
+ {
+ return node.getName();
+ }
+ }
+
+ public Font getFont(Object element)
+ {
+ TreeObject node = (TreeObject) element;
+ if (node.getType().equals(NODE_TYPE_SERVER))
+ {
+ if (node.getChildren().isEmpty())
+ {
+ return ApplicationRegistry.getFont(FONT_NORMAL);
+ }
+ else
+ {
+ return ApplicationRegistry.getFont(FONT_BOLD);
+ }
+ }
+
+ return ApplicationRegistry.getFont(FONT_NORMAL);
+ }
+ } // End of LabelProviderImpl
+
+ private static class ViewerSorterImpl extends ViewerSorter
+ {
+ public int category(Object element)
+ {
+ TreeObject node = (TreeObject) element;
+ if (node.getType().equals(MBEAN))
+ {
+ return 1;
+ }
+ if (node.getType().equals(NOTIFICATIONS))
+ {
+ return 2;
+ }
+ return 3;
+ }
+ }
+
+ /**
+ * Worker thread, which keeps looking for new ManagedObjects to be added and
+ * unregistered objects to be removed from the tree.
+ * @author Bhupendra Bhardwaj
+ */
+ private class Worker implements Runnable
+ {
+ public void run()
+ {
+ while (true)
+ {
+ if (!_managedServerMap.isEmpty())
+ {
+ refreshRemovedObjects();
+ refreshClosedServerConnections();
+ }
+
+ try
+ {
+ Thread.sleep(2000);
+ }
+ catch (InterruptedException ex)
+ {
+ //ignore
+ }
+
+ } // end of while loop
+ } // end of run method.
+ } // end of Worker class
+
+ /**
+ * Adds the mbean to the navigation tree
+ * @param mbean mbean to add to the tree
+ */
+ public void addManagedBean(ManagedBean mbean)
+ {
+ TreeObject treeServerObject = _managedServerMap.get(mbean.getServer());
+ addManagedBean(treeServerObject, mbean);
+ _treeViewer.refresh();
+ }
+
+ private void refreshRemovedObjects()
+ {
+ for (ManagedServer server : _managedServerMap.keySet())
+ {
+ final ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(server);
+ if (serverRegistry == null) // server connection is closed
+ {
+ continue;
+ }
+
+ final List<ManagedBean> removalList = serverRegistry.getObjectsToBeRemoved();
+ if (removalList != null)
+ {
+ Display display = getSite().getShell().getDisplay();
+ display.syncExec(new Runnable()
+ {
+ public void run()
+ {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ final MBeanView view = (MBeanView)window.getActivePage().findView(MBeanView.ID);
+
+ for (ManagedBean mbean : removalList)
+ {
+ TreeObject treeServerObject = _managedServerMap.get(mbean.getServer());
+
+ if(view != null)
+ {
+ //notify the MBeanView in case the unregistered mbean is being viewed
+ view.mbeanUnregistered(mbean);
+ }
+
+ removeManagedObject(treeServerObject, mbean, false);
+ }
+
+ _treeViewer.refresh();
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Gets the list of closed server connection from the ApplicationRegistry and then removes
+ * the closed server nodes from the navigation view
+ */
+ private void refreshClosedServerConnections()
+ {
+ final List<ManagedServer> closedServers = ApplicationRegistry.getClosedServers();
+ if (closedServers != null)
+ {
+ Display display = getSite().getShell().getDisplay();
+ display.syncExec(new Runnable()
+ {
+ public void run()
+ {
+ for (ManagedServer server : closedServers)
+ {
+ if(server == null)
+ {
+ continue;
+ }
+
+ TreeObject node = _managedServerMap.get(server);
+ if(node ==null)
+ {
+ continue;
+ }
+
+ removeManagedObject(node);
+ _managedServerMap.remove(server);
+ ApplicationRegistry.removeServer(server);
+ }
+
+ _treeViewer.refresh();
+ }
+ });
+ }
+ }
+
+}