diff options
Diffstat (limited to 'qpid/java/management/eclipse-plugin/src/main')
88 files changed, 20634 insertions, 0 deletions
diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Activator.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Activator.java new file mode 100644 index 0000000000..d6a9c0b0c6 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Activator.java @@ -0,0 +1,83 @@ +/* + * + * 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; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + * @author Bhupendra Bhardwaj + */ +public class Activator extends AbstractUIPlugin +{ + // The plug-in ID + public static final String PLUGIN_ID = "org.apache.qpid.management.ui"; + + // The shared instance + private static final Activator PLUGIN = new Activator(); + + /** + * The constructor + */ + public Activator() + { + + } + + /* + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception + { + super.start(context); + } + + /* + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception + { + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() + { + return PLUGIN; + } + + /** + * Returns an image descriptor for the image file at the given plug-in relative path + * + * @param path the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) + { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApiVersion.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApiVersion.java new file mode 100644 index 0000000000..2bdcd77f08 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApiVersion.java @@ -0,0 +1,110 @@ +/* + * + * 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; + +public class ApiVersion +{ + private int major; + private int minor; + + public ApiVersion(int major, int minor) + { + this.major = major; + this.minor = minor; + } + + public int getMajor() + { + return major; + } + + public int getMinor() + { + return minor; + } + + public boolean greaterThanOrEqualTo(int major, int minor) + { + if((this.major == major) && (this.minor >= minor)) + { + return true; + } + else if (this.major > major) + { + return true; + } + + return false; + } + + public boolean lessThanOrEqualTo(int major, int minor) + { + if((this.major == major) && (this.minor <= minor)) + { + return true; + } + else if (this.major < major) + { + return true; + } + + return false; + } + + public boolean greaterThan(int major, int minor) + { + if(this.major > major) + { + return true; + } + else if ((this.major == major) && (this.minor > minor)) + { + return true; + } + + return false; + } + + public boolean lessThan(int major, int minor) + { + if(this.major < major) + { + return true; + } + else if ((this.major == major) && (this.minor < minor)) + { + return true; + } + + return false; + } + + public boolean equals(int major, int minor) + { + return (this.major == major) && (this.minor == minor); + } + + public String toString() + { + return "major=" + major + ",minor=" + minor; + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Application.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Application.java new file mode 100644 index 0000000000..a1c4b7ddb0 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Application.java @@ -0,0 +1,63 @@ +/* + * + * 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; + +import org.eclipse.core.runtime.IPlatformRunnable; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; + +/** + * This class controls all aspects of the application's execution + * @author Bhupendra Bhardwaj + */ +public class Application implements IPlatformRunnable +{ + static Shell shell = null; + + /* + * The call to createAndRunWorkbench will not return until the workbench is closed. + * The SWT event loop and other low-level logistics are handled inside this method. + * @see org.eclipse.core.runtime.IPlatformRunnable#run(java.lang.Object) + */ + public Object run(Object args) throws Exception + { + Display display = PlatformUI.createDisplay(); + try + { + int returnCode = PlatformUI.createAndRunWorkbench(display, + new ApplicationWorkbenchAdvisor()); + if (returnCode == PlatformUI.RETURN_RESTART) + { + return IPlatformRunnable.EXIT_RESTART; + } + return IPlatformRunnable.EXIT_OK; + } finally + { + display.dispose(); + } + } + + static Shell getActiveShell() + { + return shell; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationActionBarAdvisor.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationActionBarAdvisor.java new file mode 100644 index 0000000000..b5c1b5074a --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationActionBarAdvisor.java @@ -0,0 +1,96 @@ +/* + * + * 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; + +import org.apache.qpid.management.ui.actions.VersionAction; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.ICoolBarManager; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; + +/** + * An action bar advisor is responsible for creating, adding, and disposing of the + * actions added to a workbench window. Each window will be populated with + * new actions. + */ +public class ApplicationActionBarAdvisor extends ActionBarAdvisor +{ + + // Actions - important to allocate these only in makeActions, and then use them + // in the fill methods. This ensures that the actions aren't recreated + // when fillActionBars is called with FILL_PROXY. + private IWorkbenchAction exitAction; + private Action _aboutAction; + + public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) + { + super(configurer); + } + + protected void makeActions(final IWorkbenchWindow window) + { + // Creates the actions and registers them. + // Registering is needed to ensure that key bindings work. + // The corresponding commands keybindings are defined in the plugin.xml file. + // Registering also provides automatic disposal of the actions when + // the window is closed. + + exitAction = ActionFactory.QUIT.create(window); + register(exitAction); + + _aboutAction = new VersionAction(window); + register(_aboutAction); + } + + + protected void fillMenuBar(IMenuManager menuBar) + { + MenuManager fileMenu = new MenuManager("&Qpid Manager", "qpidmanager"); + MenuManager helpMenu = new MenuManager("&Help", IWorkbenchActionConstants.M_HELP); + + menuBar.add(fileMenu); + // Add a group marker indicating where action set menus will appear. + menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + menuBar.add(helpMenu); + + fileMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + fileMenu.add(new Separator()); + fileMenu.add(new GroupMarker("mbeanactions")); + fileMenu.add(new Separator()); + fileMenu.add(exitAction); + + // Help + helpMenu.add(_aboutAction); + } + + protected void fillCoolBar(ICoolBarManager coolBar) + { + + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java new file mode 100644 index 0000000000..4a59176374 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java @@ -0,0 +1,189 @@ +/* + * + * 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; + +import java.io.File; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.eclipse.jface.resource.FontRegistry; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; + +/** + * Main Application Registry, which contains shared resources and map to all connected servers. + * @author Bhupendra Bhardwaj + */ +public abstract class ApplicationRegistry +{ + private static ImageRegistry imageRegistry = new ImageRegistry(); + private static FontRegistry fontRegistry = new FontRegistry(); + public static final boolean debug = Boolean.getBoolean("eclipse.consoleLog"); + public static final long timeout = Long.parseLong(System.getProperty("timeout", "15000")); + + //max supported broker management interface supported by this release of the management console + public static final int SUPPORTED_QPID_JMX_API_MAJOR_VERSION = 2; + public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 3; + + public static final String DATA_DIR = System.getProperty("user.home") + File.separator + ".qpidmc"; + + static + { + imageRegistry.put(Constants.SUCCESS_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/success.gif")); + imageRegistry.put(Constants.FAILURE_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/failure.gif")); + imageRegistry.put(Constants.CONSOLE_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/qpidmc.gif")); + imageRegistry.put(Constants.CLOSED_FOLDER_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/icon_ClosedFolder.gif")); + imageRegistry.put(Constants.OPEN_FOLDER_IMAGE, + PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER)); + imageRegistry.put(Constants.MBEAN_IMAGE, + PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT)); + imageRegistry.put(Constants.NOTIFICATION_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/notifications.gif")); + imageRegistry.put(Constants.LOGGING_MANAGEMENT_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/logging_management.gif")); + imageRegistry.put(Constants.USER_MANAGEMENT_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/user_management.gif")); + imageRegistry.put(Constants.CONFIGURATION_MANAGEMENT_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/configuration_management.gif")); + imageRegistry.put(Constants.SERVER_INFO_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/server_information.gif")); + imageRegistry.put(Constants.VHOST_MANAGER_IMAGE, + org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/virtualhost_manager.gif")); + } + + static + { + fontRegistry.put(Constants.FONT_BUTTON, new FontData[]{new FontData("Arial", 8, SWT.BOLD)} ); + fontRegistry.put(Constants.FONT_BOLD, new FontData[]{new FontData("Bold", 9, SWT.BOLD)} ); + fontRegistry.put(Constants.FONT_ITALIC, new FontData[]{new FontData("Italic", 9, SWT.ITALIC)} ); + fontRegistry.put(Constants.FONT_TABLE_CELL, new FontData[]{new FontData("Tablecell", 8, SWT.NORMAL)} ); + fontRegistry.put(Constants.FONT_NORMAL, new FontData[]{new FontData("Normal", 9, SWT.NORMAL)} ); + } + + /* + * This maps all the managed servers to the respective server registry. + */ + private static ConcurrentHashMap<ManagedServer, ServerRegistry> _serverRegistryMap = new ConcurrentHashMap<ManagedServer, ServerRegistry>(); + + // This map gets updated when a server connection closes. + private static List<ManagedServer> _closedServerList = new CopyOnWriteArrayList<ManagedServer>(); + + public static Image getImage(String key) + { + return imageRegistry.get(key); + } + + public static Font getFont(String key) + { + return fontRegistry.get(key); + } + + public static void addServer(ManagedServer server, ServerRegistry registry) + { + _serverRegistryMap.put(server, registry); + } + + public static void removeServer(ManagedServer server) + { + _serverRegistryMap.remove(server); + } + + public static ServerRegistry getServerRegistry(ManagedServer server) + { + return _serverRegistryMap.get(server); + } + + public static ServerRegistry getServerRegistry(ManagedBean mbean) + { + ManagedServer server = mbean.getServer(); + return getServerRegistry(server); + } + + public static boolean isServerConnected(ManagedServer server) + { + if(server == null) + { + //checking for null is not permitted in a CHM + return false; + } + + ServerRegistry reg = _serverRegistryMap.get(server); + if(reg !=null) + { + return !reg.isServerConnectionClosed(); + } + + return false; + } + + // remove the server from the registry + public static void serverConnectionClosed(ManagedServer server) + { + _closedServerList.add(server); + removeServer(server); + } + + // remove the server from the registry + public static void serverConnectionClosedRemotely(ManagedServer server) + { + ServerRegistry reg = _serverRegistryMap.get(server); + if(reg !=null) + { + synchronized(server) + { + if(reg.isServerConnectionClosed()) + { + //the connection closure was already processed + return; + } + + reg.serverConnectionClosed(); + } + } + + serverConnectionClosed(server); + } + + /* + * Returns the lis of closed servers. The Thread in GUI, which keeps checking for closed connection + * will check this and will remove the server links from the GUI. + */ + public static List<ManagedServer> getClosedServers() + { + if (_closedServerList.isEmpty()) + return null; + + List<ManagedServer> list = new CopyOnWriteArrayList<ManagedServer>(_closedServerList); + _closedServerList.clear(); + return list; + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchAdvisor.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchAdvisor.java new file mode 100644 index 0000000000..a46fa870e4 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchAdvisor.java @@ -0,0 +1,46 @@ +/* + * + * 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; + +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchAdvisor; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; + +/** + * This workbench advisor creates the window advisor, and specifies + * the perspective id for the initial window. + */ +public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor +{ + public static final String PERSPECTIVE_ID = "org.apache.qpid.management.ui.perspective"; + + public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) + { + return new ApplicationWorkbenchWindowAdvisor(configurer); + } + + + public String getInitialWindowPerspectiveId() + { + return PERSPECTIVE_ID; + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java new file mode 100644 index 0000000000..00574440c5 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java @@ -0,0 +1,65 @@ +/* + * + * 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; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; + +/** + * + * @author Bhupendra Bhardwaj + */ +public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor +{ + public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) + { + super(configurer); + } + + public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) + { + return new ApplicationActionBarAdvisor(configurer); + } + + public void preWindowOpen() + { + IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); + int x = Display.getDefault().getBounds().width; + int y = Display.getDefault().getBounds().height; + configurer.setInitialSize(new Point(9*x/10, 8*y/10)); + configurer.setShowCoolBar(true); + configurer.setShowStatusLine(true); + + configurer.setTitle(Constants.APPLICATION_NAME); + } + + public void postWindowCreate() + { + IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); + Shell shell = configurer.getWindow().getShell(); + shell.setImage(ApplicationRegistry.getImage(Constants.CONSOLE_IMAGE)); + } +}
\ No newline at end of file diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java new file mode 100644 index 0000000000..c8f95dd8cb --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java @@ -0,0 +1,153 @@ +/* + * + * 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; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Contains constants for the application + * @author Bhupendra Bhardwaj + * + */ +public class Constants +{ + public final static String APPLICATION_NAME = "Qpid JMX Management Console"; + public static final String DEFAULT_DOMAIN = "org.apache.qpid"; + + public final static String ACTION_REMOVE_MBEANNODE = "Remove from list"; + public final static String VALUE = "value"; + public final static String TYPE = "type"; + public final static String VERSION = "version"; + public final static String NODE_TYPE_SERVER = "server"; + public final static String NODE_TYPE_MBEANTYPE = "mbeantype"; + // currently used only for virtual host instances, but will work as general also + public final static String NODE_TYPE_TYPEINSTANCE = "mbeantype_instance"; + public final static String MBEAN = "mbean"; + public final static String ATTRIBUTE = "Attribute"; + public final static String ATTRIBUTES = "Attributes"; + public final static String NOTIFICATIONS = "Notifications"; + public final static String RESULT = "Result"; + public final static String VIRTUAL_HOST = "VirtualHost"; + public final static String DEFAULT_VH = "Default"; + public final static String DEFAULT_USERNAME = "guest"; + public final static String DEFAULT_PASSWORD = "guest"; + + public final static String USERNAME = "Username"; + public final static String PASSWORD = "Password"; + + // Attributes and operations are used to customize the GUI for Qpid. If these are changes in the + // Qpid server, then these should be updated accordingly + public final static String ATTRIBUTE_QUEUE_OWNER = "owner"; + public final static String ATTRIBUTE_QUEUE_DEPTH = "QueueDepth"; + public final static String ATTRIBUTE_QUEUE_CONSUMERCOUNT = "ActiveConsumerCount"; + public final static String OPERATION_CREATE_QUEUE = "createNewQueue"; + public final static String OPERATION_CREATE_BINDING = "createNewBinding"; + public final static String OPERATION_MOVE_MESSAGES = "moveMessages"; + + public final static String OPERATION_CREATEUSER = "createUser"; + public final static String OPERATION_DELETEUSER = "deleteUser"; + public final static String OPERATION_VIEWUSERS = "viewUsers"; + public final static String OPERATION_PARAM_USERNAME = "username"; + + public final static String OPERATION_SUCCESSFUL = "Operation successful"; + public final static String OPERATION_UNSUCCESSFUL = "Operation unsuccessful"; + + public final static String ALL = "All"; + + public final static String NAVIGATION_ROOT = "Qpid Connections"; + public final static String DESCRIPTION = " Description"; + + public final static String ADMIN_MBEAN_TYPE = "UserManagement"; + public final static String QUEUE = "Queue"; + public final static String CONNECTION ="Connection"; + public final static String EXCHANGE = "Exchange"; + public final static String EXCHANGE_TYPE = "ExchangeType"; + + public final static String DIRECT_EXCHANGE = "direct"; + public final static String FANOUT_EXCHANGE = "fanout"; + public final static String HEADERS_EXCHANGE = "headers"; + public final static String TOPIC_EXCHANGE = "topic"; + public final static List<String> DEFAULT_EXCHANGE_TYPE_VALUES = Collections.unmodifiableList( + Arrays.asList(DIRECT_EXCHANGE, FANOUT_EXCHANGE, HEADERS_EXCHANGE, TOPIC_EXCHANGE)); + public final static List<String> ATTRIBUTE_TABLE_TITLES = Collections.unmodifiableList( + Arrays.asList("Attribute Name", "Value")); + + public final static String ACTION_ADDSERVER = "New Connection"; + public final static String ACTION_RECONNECT = "Reconnect"; + public final static String ACTION_CLOSE = "Close Connection"; + public final static String ACTION_EDITATTRIBUTE = "Edit Attribute"; + public final static String ACTION_LOGIN = "Login"; + + public final static String QUEUE_SORT_BY_NAME = "Queue Name"; + public final static String QUEUE_SORT_BY_DEPTH = "Queue Depth"; + public final static String QUEUE_SORT_BY_CONSUMERCOUNT = "Consumer Count"; + public final static String QUEUE_SHOW_TEMP_QUEUES= "show temporary queues"; + + public final static String SUBSCRIBE_BUTTON = "Subscribe"; + public final static String UNSUBSCRIBE_BUTTON = "Unsubscribe"; + + + public final static String SUCCESS_IMAGE = "SuccessImage"; + public final static String FAILURE_IMAGE = "FailureImage"; + public final static String CONSOLE_IMAGE = "ConsoleImage"; + public final static String CLOSED_FOLDER_IMAGE = "ClosedFolderImage"; + public final static String OPEN_FOLDER_IMAGE = "OpenFolderImage"; + public final static String MBEAN_IMAGE = "MBeanImage"; + public final static String NOTIFICATION_IMAGE = "NotificationImage"; + public final static String LOGGING_MANAGEMENT_IMAGE = "LoggingManagementImage"; + public final static String USER_MANAGEMENT_IMAGE = "UserManagementImage"; + public final static String CONFIGURATION_MANAGEMENT_IMAGE = "ConfigurationManagementImage"; + public final static String SERVER_INFO_IMAGE = "ServerInfoImage"; + public final static String VHOST_MANAGER_IMAGE = "VhostManagerImage"; + + public final static String FONT_BUTTON = "ButtonFont"; + public final static String FONT_BOLD = "BoldFont"; + public final static String FONT_ITALIC = "ItalicFont"; + public final static String FONT_TABLE_CELL = "TableCellFont"; + public final static String FONT_NORMAL = "Normal"; + + public final static String BUTTON_DETAILS = "Details"; + public final static String BUTTON_EDIT_ATTRIBUTE = "Edit"; + public final static String BUTTON_REFRESH = "Refresh"; + public final static String BUTTON_GRAPH = "Graph"; + public final static int TIMER_INTERVAL = 5000; + public final static String BUTTON_EXECUTE = "Execute"; + public final static String BUTTON_CLEAR = "Clear"; + public final static String BUTTON_CONNECT = "Connect"; + public final static String BUTTON_CANCEL = "Cancel"; + public final static String BUTTON_UPDATE = "Update"; + + + public final static int OPERATION_IMPACT_INFO = 0; + public final static int OPERATION_IMPACT_ACTION = 1; + public final static int OPERATION_IMPACT_ACTIONINFO = 2; + public final static int OPERATION_IMPACT_UNKNOWN = 3; + + public final static String ERROR_SERVER_CONNECTION = "Server Connection Failed"; + public final static String INFO_PROTOCOL = "Please select the protocol"; + public final static String INFO_HOST_ADDRESS = "Please enter the host address"; + public final static String INFO_HOST_PORT = "Please enter the port number"; + public final static String INFO_USERNAME = "Please enter the " + USERNAME; + public final static String INFO_PASSWORD = "Please enter the " + PASSWORD; + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java new file mode 100644 index 0000000000..8ded3f35c6 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java @@ -0,0 +1,176 @@ +/* + * + * 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; + +import static org.apache.qpid.management.ui.Constants.ADMIN_MBEAN_TYPE; +import static org.apache.qpid.management.ui.Constants.CONNECTION; +import static org.apache.qpid.management.ui.Constants.DEFAULT_VH; +import static org.apache.qpid.management.ui.Constants.EXCHANGE; +import static org.apache.qpid.management.ui.Constants.QUEUE; +import static org.apache.qpid.management.ui.Constants.VIRTUAL_HOST; + +import java.util.HashMap; + +import org.apache.qpid.management.common.mbeans.ManagedBroker; + +/** + * Class representing a managed bean on the managed server + */ +public abstract class ManagedBean extends ManagedObject +{ + private String _uniqueName = ""; + private String _domain = ""; + private String _type = ""; + private String _virtualHostName = null; + private ManagedServer _server = null; + private HashMap _properties = null; + private int _version; + + public String getProperty(String key) + { + return (String) _properties.get(key); + } + + public HashMap getProperties() + { + return _properties; + } + + public void setProperties(HashMap properties) + { + this._properties = properties; + setName(getProperty("name")); + setType(getProperty("type")); + setVersion(getProperty("version")); + _virtualHostName = getProperty(VIRTUAL_HOST); + } + + public void setVersion(String version) + { + try + { + _version = Integer.parseInt(version); + } + catch (NumberFormatException nfe) + { + _version = 1; + } + + } + + public int getVersion() + { + return _version; + } + + public String getDomain() + { + return _domain; + } + + public void setDomain(String domain) + { + this._domain = domain; + } + + public ManagedServer getServer() + { + return _server; + } + + public void setServer(ManagedServer server) + { + this._server = server; + } + + public String getType() + { + return _type; + } + + public void setType(String type) + { + this._type = type; + } + + public String getUniqueName() + { + return _uniqueName; + } + + public void setUniqueName(String uniqueName) + { + this._uniqueName = uniqueName; + } + + public String getVirtualHostName() + { + // To make it work with the broker with no virtual host implementation + return _virtualHostName == null ? DEFAULT_VH : _virtualHostName; + } + + /** + * Returns mbean instance name. MBeans which have only one instance, the type attribute will be returned + * + * @return + */ + public String getInstanceName() + { + if (getName() != null) + { + return getName(); + } + else + { + return getType(); + } + } + + public boolean isQueue() + { + return _type.endsWith(QUEUE); + } + + public boolean isConnection() + { + return _type.endsWith(CONNECTION); + } + + public boolean isExchange() + { + return _type.endsWith(EXCHANGE); + } + + public boolean isVirtualHostManager() + { + return _type.endsWith(ManagedBroker.TYPE); + } + + public boolean isTempQueue() + { + return (isQueue() && getName().startsWith("tmp_")); + } + + public boolean isAdmin() + { + return _type.endsWith(ADMIN_MBEAN_TYPE); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedObject.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedObject.java new file mode 100644 index 0000000000..96e0fa46c6 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedObject.java @@ -0,0 +1,40 @@ +/* + * + * 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; + +/** + * Abstract class representing a managed object + * @author Bhupendra Bhardwaj + */ +public abstract class ManagedObject +{ + private String _name; + + public String getName() + { + return _name; + } + + public void setName(String name) + { + this._name = name; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedServer.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedServer.java new file mode 100644 index 0000000000..9ca8787bb5 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedServer.java @@ -0,0 +1,84 @@ +/* + * + * 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; + +/** + * Class representing a server being managed eg. MBeanServer + */ +public class ManagedServer extends ManagedObject +{ + private String _host; + private int _port; + private String _domain; + private String _user; + private String _password; + + public ManagedServer(String host, int port, String domain) + { + this(host, port, domain, null, null); + } + + public ManagedServer(String host, int port, String domain, String user, String password) + { + setName(host + ":" + port); + _host = host; + _port = port; + _domain = domain; + _user = user; + _password = password; + } + + public String getDomain() + { + return _domain; + } + + public String getHost() + { + return _host; + } + + public int getPort() + { + return _port; + } + + public String getPassword() + { + return _password; + } + + public void setPassword(String password) + { + _password = password; + } + + public String getUser() + { + return _user; + } + + public void setUser(String user) + { + _user = user; + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Perspective.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Perspective.java new file mode 100644 index 0000000000..f93200cadf --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Perspective.java @@ -0,0 +1,46 @@ +/* + * + * 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; + +import org.apache.qpid.management.ui.views.MBeanView; +import org.apache.qpid.management.ui.views.NavigationView; +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +/** + * + * @author Bhupendra Bhardwaj + */ +public class Perspective implements IPerspectiveFactory +{ + public void createInitialLayout(IPageLayout layout) + { + String editorArea = layout.getEditorArea(); + layout.setEditorAreaVisible(false); + + // standalone view meaning it can't be docked or stacked with other views, and it doesn't have a title bar. + layout.addStandaloneView(NavigationView.ID, true, IPageLayout.LEFT, 0.30f, editorArea); + layout.addStandaloneView(MBeanView.ID, true, IPageLayout.RIGHT, 0.70f, editorArea); + + layout.getViewLayout(NavigationView.ID).setCloseable(false); + layout.getViewLayout(MBeanView.ID).setCloseable(false); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/RefreshIntervalComboPanel.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/RefreshIntervalComboPanel.java new file mode 100644 index 0000000000..ae60467bf5 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/RefreshIntervalComboPanel.java @@ -0,0 +1,131 @@ +/* + * + * 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; + +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.MBeanView; +import org.apache.qpid.management.ui.views.NavigationView; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.menus.WorkbenchWindowControlContribution; + +public class RefreshIntervalComboPanel extends WorkbenchWindowControlContribution +{ + private Display _display = null; + private RefreshTask _refreshTask = null; + + private static int DEFAULT_INDEX = 2; //15seconds + private static final int[] INTERVALS = new int[]{5,10,15,30,60,120,300,600}; + + public RefreshIntervalComboPanel() + { + super(); + } + + public RefreshIntervalComboPanel(String id) + { + super(id); + } + + @Override + public Control createControl(Composite parent) + { + _display = parent.getDisplay(); + + Composite holder = new Composite(parent,SWT.NONE); + holder.setLayout(new GridLayout(2,false)); + holder.setLayoutData(new GridData(SWT.LEFT,SWT.TOP,false,false)); + + Label refreshLabel = new Label(holder,SWT.NONE); + refreshLabel.setLayoutData(new GridData(SWT.LEFT,SWT.TOP,false,true)); + refreshLabel.setText("Refresh Interval: "); + + final Combo combo = new Combo(holder, SWT.NONE | SWT.DROP_DOWN | SWT.READ_ONLY); + combo.setLayoutData(new GridData(SWT.LEFT,SWT.TOP,false,false)); + for(int i=0; i< INTERVALS.length ; i++) + { + combo.add(String.valueOf(INTERVALS[i]) + " seconds"); + } + combo.select(DEFAULT_INDEX); + + _refreshTask = new RefreshTask(INTERVALS[DEFAULT_INDEX]); + _display.timerExec(1000 * INTERVALS[DEFAULT_INDEX], _refreshTask); + + combo.addModifyListener( + new ModifyListener() + { + public void modifyText(final ModifyEvent e) + { + _display.timerExec(-1, _refreshTask); //cancels existing refresh runnable + _refreshTask = new RefreshTask(INTERVALS[combo.getSelectionIndex()]); + _display.timerExec(0, _refreshTask); //immediately refresh and begin new schedule + } + }); + + return holder; + } + + + private class RefreshTask implements Runnable + { + private int seconds; + + public RefreshTask(int secs) + { + this.seconds = secs; + } + + @Override + public void run() + { + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if(window != null) + { + final MBeanView mbView = (MBeanView)window.getActivePage().findView(MBeanView.ID); + + final NavigationView navView = (NavigationView)window.getActivePage().findView(NavigationView.ID); + try + { + mbView.refresh(); + navView.refresh(); + } + catch (Exception ex) + { + MBeanUtility.handleException(ex); + } + + _display.timerExec(1000 * seconds, this); + } + } + + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java new file mode 100644 index 0000000000..c3c0277f7d --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java @@ -0,0 +1,264 @@ +/* + * + * 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; + + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.qpid.management.ui.jmx.ClientListener; +import org.apache.qpid.management.ui.model.ManagedAttributeModel; +import org.apache.qpid.management.ui.model.NotificationObject; +import org.apache.qpid.management.ui.model.OperationDataModel; + +import java.util.Collections; + +public abstract class ServerRegistry +{ + private ManagedServer _managedServer = null; + + // API version for the management interface on the broker + private ApiVersion _managementApiVersion = new ApiVersion(0,0); + + // list of virtual hosts for this server + private List<String> _virtualHosts = new ArrayList<String>(); + // map of all Connection mbeans + private ConcurrentMap<String,List<ManagedBean>> _connections = new ConcurrentHashMap<String,List<ManagedBean>>(); + // map of all exchange mbeans + private ConcurrentMap<String,List<ManagedBean>> _exchanges = new ConcurrentHashMap<String,List<ManagedBean>>(); + // map of all queue mbenas + private ConcurrentMap<String,List<ManagedBean>> _queues = new ConcurrentHashMap<String,List<ManagedBean>>(); + // map of all virtual host manager mbeans + private ConcurrentMap<String,ManagedBean> _vhostManagers = new ConcurrentHashMap<String,ManagedBean>(); + + private AtomicBoolean _serverConnectionClosed = new AtomicBoolean(false); + + public ServerRegistry() + { + + } + + public ServerRegistry(ManagedServer server) + { + _managedServer = server; + } + + public void serverConnectionClosed() + { + _serverConnectionClosed.set(true); + } + + public boolean isServerConnectionClosed() + { + return _serverConnectionClosed.get(); + } + + public void setManagementApiVersion(ApiVersion mgmtApiVersion) + { + _managementApiVersion = mgmtApiVersion; + } + + public ApiVersion getManagementApiVersion() + { + return _managementApiVersion; + } + + public ManagedServer getManagedServer() + { + return _managedServer; + } + + public void setManagedServer(ManagedServer server) + { + _managedServer = server; + } + + protected void addConnectionMBean(ManagedBean mbean) + { + String vHost = mbean.getVirtualHostName(); + List<ManagedBean> vhostConnections = getVhostSubList(vHost, _connections); + vhostConnections.add(mbean); + } + + protected void addExchangeMBean(ManagedBean mbean) + { + String vHost = mbean.getVirtualHostName(); + List<ManagedBean> vhostExchanges = getVhostSubList(vHost, _exchanges); + vhostExchanges.add(mbean); + } + + protected void addQueueMBean(ManagedBean mbean) + { + String vHost = mbean.getVirtualHostName(); + List<ManagedBean> vhostQueues = getVhostSubList(vHost, _queues); + vhostQueues.add(mbean); + } + + private List<ManagedBean> getVhostSubList(String vHost, ConcurrentMap<String,List<ManagedBean>> parentList) + { + //add an empty sublist for the vhost if required + if (!parentList.containsKey(vHost)) + { + List<ManagedBean> subList = Collections.synchronizedList(new ArrayList<ManagedBean>()); + parentList.putIfAbsent(vHost, subList); + } + + return parentList.get(vHost); + } + + protected void addVirtualHostManagerMBean(ManagedBean mbean) + { + String vHost = mbean.getVirtualHostName(); + _vhostManagers.put(vHost, mbean); + } + + protected void removeVirtualHostManagerMBean(ManagedBean mbean) + { + _vhostManagers.remove(mbean.getVirtualHostName()); + } + + public ManagedBean getVirtualHostManagerMBean(String virtualHost) + { + return _vhostManagers.get(virtualHost); + } + + protected void removeConnectionMBean(ManagedBean mbean) + { + _connections.get(mbean.getVirtualHostName()).remove(mbean); + } + + protected void removeExchangeMBean(ManagedBean mbean) + { + _exchanges.get(mbean.getVirtualHostName()).remove(mbean); + } + + protected void removeQueueMBean(ManagedBean mbean) + { + _queues.get(mbean.getVirtualHostName()).remove(mbean); + } + + public List<ManagedBean> getConnections(String virtualHost) + { + return getVhostObjects(virtualHost, _connections); + } + + public List<ManagedBean> getExchanges(String virtualHost) + { + return getVhostObjects(virtualHost, _exchanges); + } + + public List<ManagedBean> getQueues(String virtualHost) + { + return getVhostObjects(virtualHost, _queues); + } + + public List<ManagedBean> getVhostObjects(String virtualHost, ConcurrentMap<String,List<ManagedBean>> parentList) + { + List<ManagedBean> objects = parentList.get(virtualHost); + + if(objects == null) + { + return new ArrayList<ManagedBean>(); + } + + synchronized (objects) + { + return new ArrayList<ManagedBean>(objects); + } + } + + //returns the requested ManagedBean, or null if it cant be found + public ManagedBean getQueue(String queueName, String virtualHost) + { + ManagedBean requestedQueue = null; + + for(ManagedBean queue : _queues.get(virtualHost)) + { + if(queueName.equals(queue.getName())) + { + requestedQueue = queue; + break; + } + } + + return requestedQueue; + } + + public void addVirtualHost(String name) + { + if (!_virtualHosts.contains(name)) + { + _virtualHosts.add(name); + } + } + + public List<String> getVirtualHosts() + { + return _virtualHosts; + } + + public abstract void setUserList(List<String> list); + + public abstract List<String> getUsernames(); + + public abstract void addManagedObject(ManagedBean key); + + public abstract List<ManagedBean> getMBeans(); + + public abstract void removeManagedObject(ManagedBean mbean); + + public abstract List<ManagedBean> getObjectsToBeRemoved(); + + public abstract ManagedAttributeModel getAttributeModel(ManagedBean mbean); + + public abstract Object getServerConnection(); + + public abstract void closeServerConnection() throws Exception; + + public abstract OperationDataModel getOperationModel(ManagedBean mbean); + + public abstract List<String> getQueueNames(String vistualHostName); + + public abstract String[] getExchangeNames(String vistualHostName); + + public abstract String[] getConnectionNames(String vistualHostName); + + public abstract List<NotificationObject> getNotifications(ManagedBean mbean); + + public abstract List<NotificationObject> getNotifications(String virtualhost); + + public abstract boolean hasSubscribedForNotifications(ManagedBean mbean, String name, String type); + + public abstract void clearNotifications(ManagedBean mbean, List<NotificationObject> list); + + public ClientListener getNotificationListener() + { + return null; + } + + public ClientListener getClientListener() + { + return null; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AbstractAction.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AbstractAction.java new file mode 100644 index 0000000000..5d892f5503 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AbstractAction.java @@ -0,0 +1,220 @@ +/* + * + * 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.actions; + +import static org.apache.qpid.management.ui.Constants.ERROR_SERVER_CONNECTION; + +import java.io.IOException; + +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLKeyException; +import javax.net.ssl.SSLPeerUnverifiedException; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ApplicationWorkbenchAdvisor; +import org.apache.qpid.management.ui.Constants; +import org.apache.qpid.management.ui.exceptions.ManagementConsoleException; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.NavigationView; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +public class AbstractAction +{ + private NavigationView _navigationView; + + protected IWorkbenchWindow _window; + + public static final String INVALID_PERSPECTIVE = "Invalid Perspective"; + public static final String CHANGE_PERSPECTIVE = "Please use the Qpid Management Perspective"; + + private static final String SSL_EMPTY_TRUSTANCHORS = "the trustAnchors parameter must be non-empty"; + private static final String SSL_UNABLE_TO_FIND_CERTPATH = "sun.security.provider.certpath.SunCertPathBuilderException: " + + "unable to find valid certification path to requested target"; + + /** + * We will cache window object in order to + * be able to provide parent shell for the message dialog. + * @see IWorkbenchWindowActionDelegate#init + */ + public void init(IWorkbenchWindow window) + { + this._window = window; + if (_window.getShell() != null) + { + _window.getShell().setImage(ApplicationRegistry.getImage(Constants.CONSOLE_IMAGE)); + } + } + + protected NavigationView getNavigationView() + { + if (_navigationView == null) + { + _navigationView = (NavigationView)_window.getActivePage().findView(NavigationView.ID); + } + + return _navigationView; + } + + protected void handleException(Throwable ex, String title, String msg) + { + //ensure first that the exception is not due to running in the wrong eclipse perspective + NavigationView view = (NavigationView)_window.getActivePage().findView(NavigationView.ID); + if (view == null) + { + IStatus status = new Status(IStatus.WARNING, ApplicationWorkbenchAdvisor.PERSPECTIVE_ID, + IStatus.OK, CHANGE_PERSPECTIVE, null); + ErrorDialog.openError(_window.getShell(), "Warning", INVALID_PERSPECTIVE, status); + return; + } + + //default title if none given + if (title == null) + { + title = ERROR_SERVER_CONNECTION; + } + + //determine the error message to display + if (msg == null) + { + if (ex instanceof SSLException) + { + if (ex instanceof SSLKeyException) + { + msg = "SSL key was invalid, please check the certificate configuration."; + //Display error dialogue and return + displayErrorDialogue(msg, title); + return; + } + else if (ex instanceof SSLPeerUnverifiedException) + { + msg = "SSL peer identity could not be verified, please ensure valid certificate configuration."; + //Display error dialogue and return + displayErrorDialogue(msg, title); + return; + } + else if (ex instanceof SSLHandshakeException) + { + if (ex.getMessage().contains(SSL_UNABLE_TO_FIND_CERTPATH)) + { + msg = "Unable to certify the provided SSL certificate using the current SSL trust store."; + } + else + { + //cause unknown, provide a trace too + MBeanUtility.printStackTrace(ex); + msg = "SSL handhshake error."; + } + //Display error dialogue and return + displayErrorDialogue(msg, title); + return; + } + else + { + //general SSL Exception. + if (ex.getMessage().contains(SSL_EMPTY_TRUSTANCHORS)) + { + msg = "Unable to locate the specified SSL certificate trust store, please check the configuration."; + } + else + { + //cause unknown, print stack trace + MBeanUtility.printStackTrace(ex); + msg = "SSL connection error."; + } + //Display error dialogue and return + displayErrorDialogue(msg, title); + return; + } + } + else if (ex instanceof IOException || ex instanceof SecurityException ) + { + msg = ex.getMessage(); + + //if msg is still null, try reporting the cause. + if ((msg == null) && (ex.getCause() != null)) + { + msg = ex.getCause().getMessage(); + } + + //Display error dialogue and return + displayErrorDialogue(msg, title); + return; + } + else if (ex instanceof ManagementConsoleException) + { + msg = ex.getMessage(); + displayErrorDialogue(msg, title); + return; + } + else + { + //Unknown exception type/reason. + msg = ex.getMessage(); + } + + //if msg is still null, try reporting the cause. + if ((msg == null) && (ex.getCause() != null)) + { + msg = ex.getCause().getMessage(); + } + + //failing all else, default non-descript error message. + if (msg == null) + { + msg = "An unknown error has occured."; + } + } + + //Display error dialogue and print the exception stack trace + MBeanUtility.printStackTrace(ex); + displayErrorDialogue(msg, title); + } + + private void displayErrorDialogue(String msg, String title) + { + IStatus status = new Status(IStatus.ERROR, ApplicationWorkbenchAdvisor.PERSPECTIVE_ID, + IStatus.OK, msg, null); + ErrorDialog.openError(_window.getShell(), "Error", title, status); + } + + /** + * Selection in the workbench has been changed. We can change the state of the 'real' action here + * if we want, but this can only happen after the delegate has been created. + * @see IWorkbenchWindowActionDelegate#selectionChanged + */ + public void selectionChanged(IAction action, ISelection selection) { + } + + /** + * We can use this method to dispose of any system resources we previously allocated. + * @see IWorkbenchWindowActionDelegate#dispose + */ + public void dispose() { + + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java new file mode 100644 index 0000000000..e487c02a67 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java @@ -0,0 +1,313 @@ +/* + * + * 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.actions; + +import static org.apache.qpid.management.ui.Constants.*; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.exceptions.InfoRequiredException; +import org.apache.qpid.management.ui.views.NumberVerifyListener; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.action.IAction; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +public class AddServer extends AbstractAction implements IWorkbenchWindowActionDelegate +{ + private String _host; + private String _port; + private String _domain = DEFAULT_DOMAIN; + private String _user; + private String _password; + + private boolean _addServer; + + public AddServer() + { + + } + + public void run(IAction action) + { + if(_window == null) + return; + + reset(); + createAddServerPopup(); + try + { + if (_addServer) + { + getNavigationView().addNewServer(_host, Integer.parseInt(_port), _domain, _user, _password); + } + } + catch(InfoRequiredException ex) + { + ViewUtility.popupInfoMessage(ACTION_ADDSERVER, ex.getMessage()); + } + catch (Exception ex) + { + handleException(ex, null, null); + } + } + + private void reset() + { + _addServer = false; + _host = null; + _port = null; + _user = null; + _password = null; + } + + /** + * Creates the shell and then opens the popup where user can enter new connection details. + * Connects to the new server and adds the server in the navigation page. + * Pops up any error occured in connecting to the new server + */ + private void createAddServerPopup() + { + final Shell appShell = _window.getShell(); + + Display display = Display.getCurrent(); + final Shell shell = new Shell(display, SWT.BORDER | SWT.CLOSE); + shell.setText(ACTION_ADDSERVER); + shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE)); + shell.setLayout(new GridLayout()); + + createWidgets(shell); + shell.pack(); + + //get current size dialog, and application window size and location + int appWidth = appShell.getBounds().width; + int appHeight = appShell.getBounds().height; + int appLocX = appShell.getBounds().x; + int appLocY = appShell.getBounds().y; + int currentShellWidth = shell.getSize().x; + int currentShellHeight = shell.getSize().y; + + //default sizes for the dialog + int minShellWidth = 425; + int minShellHeight= 265; + //ensure this is large enough, increase it if its not + int newShellWidth = currentShellWidth > minShellWidth ? currentShellWidth : minShellWidth; + int newShellHeight = currentShellHeight > minShellHeight ? currentShellHeight : minShellHeight; + + //set the final size and centre the dialog within the app window + shell.setBounds((appWidth - newShellWidth)/2 + appLocX, (appHeight - newShellHeight)/2 + appLocY, newShellWidth, newShellHeight); + + shell.open(); + _window.getShell().setEnabled(false); + + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + { + display.sleep(); + } + } + + // enable the main shell + _window.getShell().setEnabled(true); + _window.getShell().open(); + } + + // Creates SWT widgets for the user to add server connection details. + // Adds listeners to the widgets to take appropriate action + private void createWidgets(final Shell shell) + { + Composite composite = new Composite(shell, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + GridLayout layout = new GridLayout(2, false); + layout.horizontalSpacing = 10; + layout.verticalSpacing = 10; + layout.marginHeight = 20; + layout.marginWidth = 20; + composite.setLayout(layout); + + /* Commenting this, as there is only one protocol at the moment. + * This can be uncommented and enhanced, if more protocols are added in future + Label name = new Label(composite, SWT.NONE); + name.setText("Connection Type"); + GridData layoutData = new GridData(SWT.TRAIL, SWT.TOP, false, false); + name.setLayoutData(layoutData); + + final Combo comboTransport = new Combo(composite, SWT.READ_ONLY); + comboTransport.setItems(CONNECTION_PROTOCOLS); + comboTransport.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + comboTransport.select(0); + */ + + Label host = new Label(composite, SWT.NONE); + host.setText("Host"); + host.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); + + final Text textHost = new Text(composite, SWT.BORDER); + textHost.setText(""); + textHost.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + textHost.setFocus(); + + Label port = new Label(composite, SWT.NONE); + port.setText("Port"); + port.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); + + final Text textPort = new Text(composite, SWT.BORDER); + textPort.setText(""); + textPort.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + // Verify if the value entered is numeric + textPort.addVerifyListener(new NumberVerifyListener()); + + Label user = new Label(composite, SWT.NONE); + user.setText(USERNAME); + user.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); + + final Text textUser = new Text(composite, SWT.BORDER); + textUser.setText(""); + textUser.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Label password = new Label(composite, SWT.NONE); + password.setText(PASSWORD); + password.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); + + final Text textPwd = new Text(composite, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD); + textPwd.setText(""); + //textPwd.setEchoChar('*'); + textPwd.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + //Get the text widgets + Control[] widgets = composite.getChildren(); + for (int i=0; i < widgets.length; i++) + { + widgets[i].addKeyListener(new KeyAdapter() + { + public void keyPressed(KeyEvent event) + { + if (event.character == SWT.ESC) + { + //Escape key acts as cancel on all widgets + shell.dispose(); + } + } + }); + } + + Composite buttonsComposite = new Composite(composite, SWT.NONE); + buttonsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); + buttonsComposite.setLayout(new GridLayout(2, true)); + + final Button connectButton = new Button(buttonsComposite, SWT.PUSH | SWT.CENTER); + connectButton.setText(BUTTON_CONNECT); + GridData gridData = new GridData (SWT.TRAIL, SWT.BOTTOM, true, true); + gridData.widthHint = 100; + connectButton.setLayoutData(gridData); + connectButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + connectButton.addSelectionListener(new SelectionAdapter(){ + public void widgetSelected(SelectionEvent event) + { + _host = textHost.getText(); + if ((_host == null) || (_host.trim().length() == 0)) + { + ViewUtility.popupInfoMessage(ACTION_ADDSERVER, INFO_HOST_ADDRESS); + textHost.setText(""); + textHost.setFocus(); + return; + } + + _port = textPort.getText(); + if ((_port == null) || (_port.trim().length() == 0)) + { + ViewUtility.popupInfoMessage(ACTION_ADDSERVER, INFO_HOST_PORT); + textPort.setText(""); + textPort.setFocus(); + return; + } + + _user = textUser.getText(); + if ((_user == null) || (_user.trim().length() == 0)) + { + ViewUtility.popupInfoMessage(ACTION_ADDSERVER, INFO_USERNAME); + textUser.setText(""); + textUser.setFocus(); + return; + } + + _password = textPwd.getText(); + if (_password == null) + { + ViewUtility.popupInfoMessage(ACTION_ADDSERVER, INFO_PASSWORD); + textPwd.setText(""); + textPwd.setFocus(); + return; + } + + _addServer = true; + shell.dispose(); + } + }); + + final Button cancelButton = new Button(buttonsComposite, SWT.PUSH); + cancelButton.setText(BUTTON_CANCEL); + gridData = new GridData (SWT.LEAD, SWT.BOTTOM, true, true); + gridData.widthHint = 100; + cancelButton.setLayoutData(gridData); + cancelButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent event) + { + shell.dispose(); + } + }); + + //Get the ok/cancel button widgets and add a new key listener + widgets = buttonsComposite.getChildren(); + for (int i=0; i < widgets.length; i++) + { + widgets[i].addKeyListener(new KeyAdapter() + { + public void keyPressed(KeyEvent event) + { + if (event.character == SWT.ESC) + { + //Escape key acts as cancel on all widgets + shell.dispose(); + } + } + }); + } + + shell.setDefaultButton(connectButton); + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/BackAction.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/BackAction.java new file mode 100644 index 0000000000..2998c5db53 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/BackAction.java @@ -0,0 +1,59 @@ +/* + * + * 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.actions; + +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.MBeanView; +import org.eclipse.jface.action.Action; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; + + +public class BackAction extends Action implements IWorkbenchAction +{ + private static final String ID = "org.apache.qpid.management.ui.actions.back"; + + public BackAction() + { + setText("Back"); + setImageDescriptor(org.apache.qpid.management.ui.Activator.getImageDescriptor("/icons/back.gif")); + setId(ID); + } + + public void run() + { + MBeanView mbeanview = (MBeanView)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(MBeanView.ID); + try + { + mbeanview.back(); + } + catch (Exception ex) + { + MBeanUtility.handleException(ex); + } + + } + + public void dispose() + { + + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/CloseConnection.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/CloseConnection.java new file mode 100644 index 0000000000..a3e52149df --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/CloseConnection.java @@ -0,0 +1,56 @@ +/* + * + * 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.actions; + +import static org.apache.qpid.management.ui.Constants.ACTION_CLOSE; +import org.apache.qpid.management.ui.exceptions.InfoRequiredException; +import org.apache.qpid.management.ui.views.NavigationView; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.action.IAction; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +public class CloseConnection extends AbstractAction implements IWorkbenchWindowActionDelegate +{ + public CloseConnection() + { + + } + + public void run(IAction action) + { + if(_window != null) + { + NavigationView view = (NavigationView)_window.getActivePage().findView(NavigationView.ID); + try + { + view.disconnect(); + } + catch(InfoRequiredException ex) + { + ViewUtility.popupInfoMessage(ACTION_CLOSE, ex.getMessage()); + } + catch(Exception ex) + { + handleException(ex, null, null); + } + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java new file mode 100644 index 0000000000..5eb9d9a168 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java @@ -0,0 +1,264 @@ +/* + * + * 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.actions; + +import static org.apache.qpid.management.ui.Constants.ACTION_LOGIN; +import static org.apache.qpid.management.ui.Constants.CONSOLE_IMAGE; +import static org.apache.qpid.management.ui.Constants.INFO_PASSWORD; +import static org.apache.qpid.management.ui.Constants.INFO_USERNAME; +import static org.apache.qpid.management.ui.Constants.PASSWORD; +import static org.apache.qpid.management.ui.Constants.USERNAME; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.Constants; +import org.apache.qpid.management.ui.exceptions.InfoRequiredException; +import org.apache.qpid.management.ui.views.TreeObject; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.action.IAction; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +public class ReconnectServer extends AbstractAction implements IWorkbenchWindowActionDelegate +{ + private String _title; + private String _serverName; + private String _user; + private String _password; + private boolean _connect; + + public void run(IAction action) + { + if(_window == null) + return; + + try + { + reset(); + // Check if a server node is selected to be reconnected. + TreeObject serverNode = getNavigationView().getSelectedServerNode(); + _serverName = serverNode.getName(); + _title = ACTION_LOGIN + " (" + _serverName + ")"; + + // Get the login details(username/password) + createLoginPopup(); + + if (_connect) + { + // Connect the server + getNavigationView().reconnect(_user, _password); + } + } + catch(InfoRequiredException ex) + { + ViewUtility.popupInfoMessage("Reconnect Qpid server", ex.getMessage()); + } + catch (Exception ex) + { + handleException(ex, null, null); + } + } + + private void reset() + { + _connect = false; + _user = null; + _password = null; + } + + // Create the login popup fot th user to enter usernaem and password + private void createLoginPopup() + { + final Shell appShell = _window.getShell(); + + Display display = Display.getCurrent(); + final Shell shell = new Shell(display, SWT.BORDER | SWT.CLOSE); + shell.setText(_title); + shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE)); + shell.setLayout(new GridLayout()); + + createWidgets(shell); + shell.pack(); + + //get current size dialog, and application window size and location + int appWidth = appShell.getBounds().width; + int appHeight = appShell.getBounds().height; + int appLocX = appShell.getBounds().x; + int appLocY = appShell.getBounds().y; + int currentShellWidth = shell.getSize().x; + int currentShellHeight = shell.getSize().y; + + //default sizes for the dialog + int minShellWidth = 350; + int minShellHeight= 200; + //ensure this is large enough, increase it if its not + int newShellWidth = currentShellWidth > minShellWidth ? currentShellWidth : minShellWidth; + int newShellHeight = currentShellHeight > minShellHeight ? currentShellHeight : minShellHeight; + + //set the final size and centre the dialog within the app window + shell.setBounds((appWidth - newShellWidth)/2 + appLocX, (appHeight - newShellHeight)/2 + appLocY, newShellWidth, newShellHeight); + + shell.open(); + _window.getShell().setEnabled(false); + + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + { + display.sleep(); + } + } + + // enable the main shell + _window.getShell().setEnabled(true); + _window.getShell().open(); + } + + // Creates the SWT widgets in the popup shell, to enter username and password. + // Adds listeners to the widgets to take appropriate action + private void createWidgets(final Shell shell) + { + Composite composite = new Composite(shell, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + GridLayout layout = new GridLayout(2, false); + layout.horizontalSpacing = 10; + layout.verticalSpacing = 10; + layout.marginHeight = 20; + layout.marginWidth = 20; + composite.setLayout(layout); + + Label user = new Label(composite, SWT.NONE); + user.setText(USERNAME); + user.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); + + final Text textUser = new Text(composite, SWT.BORDER); + textUser.setText(""); + textUser.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + // Put cursor on this field + textUser.setFocus(); + + Label password = new Label(composite, SWT.NONE); + password.setText(PASSWORD); + password.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); + + final Text textPwd = new Text(composite, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD); + textPwd.setText(""); + textPwd.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + //Get the text widgets + Control[] widgets = composite.getChildren(); + for (int i=0; i < widgets.length; i++) + { + widgets[i].addKeyListener(new KeyAdapter() + { + public void keyPressed(KeyEvent event) + { + if (event.character == SWT.ESC) + { + //Escape key acts as cancel on all widgets + shell.dispose(); + } + } + }); + } + + Composite buttonsComposite = new Composite(composite, SWT.NONE); + buttonsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); + buttonsComposite.setLayout(new GridLayout(2, true)); + + final Button connectButton = new Button(buttonsComposite, SWT.PUSH | SWT.CENTER); + connectButton.setText(Constants.BUTTON_CONNECT); + GridData gridData = new GridData (SWT.TRAIL, SWT.BOTTOM, true, true); + gridData.widthHint = 100; + connectButton.setLayoutData(gridData); + connectButton.setFont(ApplicationRegistry.getFont(Constants.FONT_BUTTON)); + connectButton.addSelectionListener(new SelectionAdapter(){ + public void widgetSelected(SelectionEvent event) + { + _user = textUser.getText(); + if ((_user == null) || (_user.trim().length() == 0)) + { + ViewUtility.popupInfoMessage(_title, INFO_USERNAME); + textUser.setText(""); + textUser.setFocus(); + return; + } + + _password = textPwd.getText(); + if (_password == null) + { + ViewUtility.popupInfoMessage(_title, INFO_PASSWORD); + textPwd.setText(""); + textPwd.setFocus(); + return; + } + + _connect = true; + shell.dispose(); + } + }); + + final Button cancelButton = new Button(buttonsComposite, SWT.PUSH); + cancelButton.setText(Constants.BUTTON_CANCEL); + gridData = new GridData (SWT.LEAD, SWT.BOTTOM, true, true); + gridData.widthHint = 100; + cancelButton.setLayoutData(gridData); + cancelButton.setFont(ApplicationRegistry.getFont(Constants.FONT_BUTTON)); + cancelButton.addSelectionListener(new SelectionAdapter(){ + public void widgetSelected(SelectionEvent event) + { + shell.dispose(); + } + }); + + //Get the ok/cancel button widgets and add a new key listener + widgets = buttonsComposite.getChildren(); + for (int i=0; i < widgets.length; i++) + { + widgets[i].addKeyListener(new KeyAdapter() + { + public void keyPressed(KeyEvent event) + { + if (event.character == SWT.ESC) + { + //Escape key acts as cancel on all widgets + shell.dispose(); + } + } + }); + } + + shell.setDefaultButton(connectButton); + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/Refresh.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/Refresh.java new file mode 100644 index 0000000000..dd4cbffd84 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/Refresh.java @@ -0,0 +1,53 @@ +/* + * + * 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.actions; + +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.MBeanView; +import org.apache.qpid.management.ui.views.NavigationView; +import org.eclipse.jface.action.IAction; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +/** + * This action refreshes both the views -Navigation and MBeanView + * @author Bhupendra Bhardwaj + */ +public class Refresh extends AbstractAction implements IWorkbenchWindowActionDelegate +{ + public void run(IAction action) + { + if(_window != null) + { + NavigationView view = (NavigationView)_window.getActivePage().findView(NavigationView.ID); + view.refresh(); + + MBeanView mbeanview = (MBeanView)_window.getActivePage().findView(MBeanView.ID); + try + { + mbeanview.refresh(); + } + catch (Exception ex) + { + MBeanUtility.handleException(ex); + } + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/RemoveServer.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/RemoveServer.java new file mode 100644 index 0000000000..e329255414 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/RemoveServer.java @@ -0,0 +1,50 @@ +/* + * + * 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.actions; + +import org.apache.qpid.management.ui.exceptions.InfoRequiredException; +import org.apache.qpid.management.ui.views.NavigationView; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.action.IAction; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +public class RemoveServer extends AbstractAction implements IWorkbenchWindowActionDelegate +{ + public void run(IAction action) + { + if(_window != null) + { + NavigationView view = (NavigationView)_window.getActivePage().findView(NavigationView.ID); + try + { + view.removeServer(); + } + catch(InfoRequiredException ex) + { + ViewUtility.popupInfoMessage("Remove Qpid server", ex.getMessage()); + } + catch(Exception ex) + { + handleException(ex, "Server could not be removed", null); + } + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/VersionAction.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/VersionAction.java new file mode 100644 index 0000000000..be69fadbe8 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/VersionAction.java @@ -0,0 +1,94 @@ +/* + * + * 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.actions; + +import java.io.InputStream; +import java.util.Properties; + +import org.apache.qpid.management.ui.Constants; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.ui.IWorkbenchWindow; + +public class VersionAction extends Action +{ + private IWorkbenchWindow _window; + public static final String VERSION_RESOURCE = "qpidversion.properties"; + + public static final String PRODUCT_NAME_PROPERTY = "qpid.name"; + public static final String RELEASE_VERSION_PROPERTY = "qpid.version"; + public static final String BUILD_VERSION_PROPERTY = "qpid.svnversion"; + + private static final String DEFAULT = "unknown"; + private static String _releaseVersion; + private static String _buildVersion; + private static String _text; + + static + { + Properties props = new Properties(); + try + { + InputStream propertyStream = VersionAction.class.getClassLoader().getResourceAsStream(VERSION_RESOURCE); + if (propertyStream != null) + { + props.load(propertyStream); + _releaseVersion = readPropertyValue(props, RELEASE_VERSION_PROPERTY); + _buildVersion = readPropertyValue(props, BUILD_VERSION_PROPERTY); + _text = "Build Version : " + _buildVersion + "\n" + + "Release Version : " + _releaseVersion; + } + else + { + _text = "Build Version : \n" + + "Release Version : "; + } + } + catch (Exception ex) + { + MBeanUtility.printStackTrace(ex); + } + } + + public VersionAction(IWorkbenchWindow window) + { + _window = window; + setText("About " + Constants.APPLICATION_NAME); + setId("qpidmc.about"); + setActionDefinitionId("qpidmc.about"); + } + + private static String readPropertyValue(Properties props, String propertyName) + { + String retVal = (String) props.get(propertyName); + if (retVal == null) + { + retVal = DEFAULT; + } + return retVal; + } + + public void run() + { + MessageDialog.openInformation(_window.getShell(), Constants.APPLICATION_NAME, _text); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/exceptions/InfoRequiredException.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/exceptions/InfoRequiredException.java new file mode 100644 index 0000000000..672426a59d --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/exceptions/InfoRequiredException.java @@ -0,0 +1,36 @@ +/* + * + * 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.exceptions; + +public class InfoRequiredException extends Exception +{ + private static final long serialVersionUID = 1L; + + public InfoRequiredException(String message) + { + super(message); + } + + public InfoRequiredException(String msg, Throwable t) + { + super(msg, t); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/exceptions/ManagementConsoleException.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/exceptions/ManagementConsoleException.java new file mode 100644 index 0000000000..17c127c01a --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/exceptions/ManagementConsoleException.java @@ -0,0 +1,31 @@ +/* + * + * 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.exceptions; + +@SuppressWarnings("serial") +public class ManagementConsoleException extends Exception +{ + public ManagementConsoleException(String message) + { + super(message); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java new file mode 100644 index 0000000000..6fa78b1d36 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java @@ -0,0 +1,84 @@ + +/* + * + * 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.jmx; + +import javax.management.MBeanServerNotification; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnectionNotification; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ManagedServer; + + +public class ClientListener implements NotificationListener +{ + protected ManagedServer server = null; + protected JMXServerRegistry serverRegistry = null; + + public ClientListener(ManagedServer server) + { + this.server = server; + serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(server); + } + + public void handleNotification(Notification notification, Object handback) + { + String type = notification.getType(); + + if(notification instanceof MBeanServerNotification) + { + ObjectName objName = ((MBeanServerNotification)notification).getMBeanName(); + + if (MBeanServerNotification.REGISTRATION_NOTIFICATION.equals(type)) + { + getServerRegistry().registerManagedObject(objName); + } + else if (MBeanServerNotification.UNREGISTRATION_NOTIFICATION.equals(type)) + { + getServerRegistry().unregisterManagedObject(objName); + } + } + else if (JMXConnectionNotification.FAILED.equals(type)) + { + ApplicationRegistry.serverConnectionClosedRemotely(server); + MBeanUtility.printOutput("JMX Connection to " + server.getName() + " failed."); + } + else if (JMXConnectionNotification.CLOSED.equals(type)) + { + ApplicationRegistry.serverConnectionClosedRemotely(server); + MBeanUtility.printOutput("JMX Connection to " + server.getName() + " was closed."); + } + } + + protected JMXServerRegistry getServerRegistry() + { + if (serverRegistry == null) + serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(server); + + return serverRegistry; + } + public ManagedServer getServer() + { + return server; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientNotificationListener.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientNotificationListener.java new file mode 100644 index 0000000000..2af8e681ae --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientNotificationListener.java @@ -0,0 +1,40 @@ +/* + * + * 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.jmx; + +import javax.management.Notification; +import javax.management.ObjectName; + +import org.apache.qpid.management.ui.ManagedServer; + +public class ClientNotificationListener extends ClientListener +{ + public ClientNotificationListener(ManagedServer server) + { + super(server); + } + + public void handleNotification(Notification notification, Object handback) + { + ObjectName objName = (ObjectName)notification.getSource(); + getServerRegistry().addNotification(objName, notification); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java new file mode 100644 index 0000000000..a8fb864cf6 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXManagedObject.java @@ -0,0 +1,71 @@ +/* + * + * 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.jmx; + +import java.util.HashMap; +import java.util.Map; + +import javax.management.ObjectName; + +import org.apache.qpid.management.ui.ManagedBean; + + +public class JMXManagedObject extends ManagedBean +{ + private ObjectName _objName; + + public JMXManagedObject(ObjectName objName) + { + super(); + this._objName = objName; + setUniqueName(_objName.toString()); + setDomain(_objName.getDomain()); + + HashMap<String,String> props = new HashMap<String,String>(_objName.getKeyPropertyList()); + + for(Map.Entry<String,String> entry : props.entrySet()) + { + String value = entry.getValue(); + + if(value != null) + { + try + { + //if the name is quoted in the ObjectName, unquote it + value = ObjectName.unquote(value); + entry.setValue(value); + } + catch(IllegalArgumentException e) + { + //ignore, this just means the name is not quoted + //and can be left unchanged + } + } + } + + super.setProperties(props); + } + + public ObjectName getObjectName() + { + return _objName; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java new file mode 100644 index 0000000000..717f781334 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java @@ -0,0 +1,612 @@ +/* + * + * 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.jmx; + +import static org.apache.qpid.management.ui.Constants.ALL; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.management.MBeanInfo; +import javax.management.MBeanServerConnection; +import javax.management.Notification; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; + +import org.apache.qpid.management.common.JMXConnnectionFactory; +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.ManagedServer; +import org.apache.qpid.management.ui.ServerRegistry; +import org.apache.qpid.management.ui.model.ManagedAttributeModel; +import org.apache.qpid.management.ui.model.NotificationInfoModel; +import org.apache.qpid.management.ui.model.NotificationObject; +import org.apache.qpid.management.ui.model.OperationDataModel; + + +public class JMXServerRegistry extends ServerRegistry +{ + private ObjectName _serverObjectName = null; + private JMXConnector _jmxc = null; + private MBeanServerConnection _mbsc = null; + private String _securityMechanism = null; + + private List<String> _usersList; + // When an mbean gets removed from mbean server, then the notification listener + // will add that mbean in this list. + private List<ManagedBean> _mbeansToBeRemoved = new ArrayList<ManagedBean>(); + + // Map containing all managed beans and mapped with unique mbean name + private HashMap<String, ManagedBean> _mbeansMap = new HashMap<String, ManagedBean>(); + // Map containing MBeanInfo for all mbeans and mapped with unique mbean name + private HashMap<String, MBeanInfo> _mbeanInfoMap = new HashMap<String, MBeanInfo>(); + // Map containing attribute model for all mbeans and mapped with unique mbean name + private HashMap<String, ManagedAttributeModel> _attributeModelMap = new HashMap<String, ManagedAttributeModel>(); + // Map containing operation model for all mbeans and mapped with unique mbean name + private HashMap<String, OperationDataModel> _operationModelMap = new HashMap<String, OperationDataModel>(); + // Map containing NotificationInfo for all mbeans and mapped with unique mbean name + private HashMap<String, List<NotificationInfoModel>> _notificationInfoMap = new HashMap<String, List<NotificationInfoModel>>(); + // Map containing all notifications sent for all mbeans, which are registered for notification + private HashMap<String, List<NotificationObject>> _notificationsMap = new HashMap<String, List<NotificationObject>>(); + // For mbeans which have subscribed for a notification type + // mbean unique name mapped with notification map. Notification map contains list of notification type + // mapped with notification name. Notification type list contains those notification types, + // which are subscribed for notification. + private HashMap<String, HashMap<String, List<String>>> _subscribedNotificationMap = new HashMap<String, HashMap<String, List<String>>>(); + + // listener for registration or unregistratioj of mbeans on mbean server + private ClientNotificationListener _notificationListener = null; + // listener for server connection. Receives notification if server connection goes down + private ClientListener _clientListener = null; + + public JMXServerRegistry(ManagedServer server) throws Exception + { + super(server); + + _jmxc = JMXConnnectionFactory.getJMXConnection( + ApplicationRegistry.timeout, server.getHost(), + server.getPort(), server.getUser(), server.getPassword()); + + _mbsc = _jmxc.getMBeanServerConnection(); + + _clientListener = new ClientListener(server); + _notificationListener = new ClientNotificationListener(server); + + _jmxc.addConnectionNotificationListener(_clientListener, null, null); + _serverObjectName = new ObjectName("JMImplementation:type=MBeanServerDelegate"); + _mbsc.addNotificationListener(_serverObjectName, _clientListener, null, null); + + } + + public MBeanServerConnection getServerConnection() + { + return _mbsc; + } + + + public String getSecurityMechanism() + { + return _securityMechanism; + } + + /** + * removes all listeners from the mbean server. This is required when user + * disconnects the Qpid server connection + */ + public void closeServerConnection() throws IOException + { + if(isServerConnectionClosed()) + { + //connection was already closed + return; + } + + try + { + //remove the listener from the JMXConnector + if (_jmxc != null && _clientListener != null) + { + _jmxc.removeConnectionNotificationListener(_clientListener); + } + } + catch (Exception e) + { + //ignore + } + + try + { + //remove the listener from the MBeanServerDelegate MBean + if (_mbsc != null && _clientListener != null) + { + _mbsc.removeNotificationListener(_serverObjectName, _clientListener); + } + } + catch (Exception e) + { + //ignore + } + + if (_mbsc != null && _clientListener != null) + { + //remove any listeners from the Qpid MBeans + for (String mbeanName : _subscribedNotificationMap.keySet()) + { + try + { + _mbsc.removeNotificationListener(new ObjectName(mbeanName), _notificationListener); + } + catch (Exception e) + { + //ignore + } + } + } + + //close the JMXConnector + if (_jmxc != null) + { + _jmxc.close(); + } + + serverConnectionClosed(); + } + + public ManagedBean getManagedObject(String uniqueName) + { + return _mbeansMap.get(uniqueName); + } + + public void addManagedObject(ManagedBean mbean) + { + if (mbean.isQueue()) + { + addQueueMBean(mbean); + } + else if (mbean.isExchange()) + { + addExchangeMBean(mbean); + } + else if (mbean.isConnection()) + { + addConnectionMBean(mbean); + } + else if (mbean.isVirtualHostManager()) + { + addVirtualHostManagerMBean(mbean); + } + + addVirtualHost(mbean.getVirtualHostName()); + _mbeansMap.put(mbean.getUniqueName(), mbean); + } + + public void removeManagedObject(ManagedBean mbean) + { + if (mbean == null) + { + return; + } + + _mbeansMap.remove(mbean.getUniqueName()); + + if (mbean.isQueue()) + { + removeQueueMBean(mbean); + } + else if (mbean.isExchange()) + { + removeExchangeMBean(mbean); + } + else if (mbean.isConnection()) + { + removeConnectionMBean(mbean); + } + else if (mbean.isVirtualHostManager()) + { + removeVirtualHostManagerMBean(mbean); + } + } + + public void putMBeanInfo(ManagedBean mbean, MBeanInfo mbeanInfo) + { + _mbeanInfoMap.put(mbean.getUniqueName(), mbeanInfo); + } + public MBeanInfo getMBeanInfo(ManagedBean mbean) + { + return _mbeanInfoMap.get(mbean.getUniqueName()); + } + + public List<ManagedBean> getMBeans() + { + return new ArrayList<ManagedBean>(_mbeansMap.values()); + } + + public void setNotificationInfo(ManagedBean mbean, List<NotificationInfoModel>value) + { + _notificationInfoMap.put(mbean.getUniqueName(), value); + } + + public List<NotificationInfoModel> getNotificationInfo(ManagedBean mbean) + { + return _notificationInfoMap.get(mbean.getUniqueName()); + } + + public void addNotification(ObjectName objName, Notification notification) + { + List<NotificationObject> list = _notificationsMap.get(objName.toString()); + NotificationObject obj = new NotificationObject(notification.getSequenceNumber(), + new Date(notification.getTimeStamp()), + notification.getMessage(), + notification.getSource(), + notification.getType()); + + if (list == null) + { + list = new ArrayList<NotificationObject>(); + _notificationsMap.put(objName.toString(), list); + } + + list.add(obj); + } + + /** + * Returns all the notification objects for a given mbean. If mbean is null, it returns + * notification objects for all the mbeans. + */ + public List<NotificationObject> getNotifications(ManagedBean mbean) + { + if (mbean == null) + { + List<NotificationObject> totalList = new ArrayList<NotificationObject>(); + for (List<NotificationObject> list : _notificationsMap.values()) + { + totalList.addAll(list); + } + return totalList; + } + else + { + return _notificationsMap.get(mbean.getUniqueName()); + } + } + + public List<NotificationObject> getNotifications(String virtualhost) + { + List<NotificationObject> vhostNotificationsList = new ArrayList<NotificationObject>(); + + //iterate over all the notification lists for mbeans with subscribed notifications + for (List<NotificationObject> list : _notificationsMap.values()) + { + if(list == null || list.isEmpty()) + { + continue; + } + + //Check the source vhost of the first notification + NotificationObject notification = list.get(0); + + if (notification != null) + { + String sourceVhost = notification.getSourceVirtualHost(); + if(sourceVhost != null) + { + if(sourceVhost.equalsIgnoreCase(virtualhost)) + { + //If it matches, add the entire list as they are from the same vhost (same source mbean) + vhostNotificationsList.addAll(list); + } + } + } + } + + return vhostNotificationsList; + } + + public void clearNotifications(ManagedBean mbean, List<NotificationObject> list) + { + if (mbean == null) + { + if (list == null || list.isEmpty()) + { + // All notifications of all mbeans to be cleared + _notificationsMap.clear(); + } + else + { + // Clear the selected notifications + for (NotificationObject obj : list) + { + mbean = _mbeansMap.get(obj.getSource().toString()); + List<NotificationObject> nList = _notificationsMap.get(mbean.getUniqueName()); + if (nList != null && !nList.isEmpty()) + { + nList.remove(obj); + } + } + } + } + else + { + if (list == null || list.isEmpty()) + { + // All notifications of this mbean to be cleared + List<NotificationObject> nList = _notificationsMap.get(mbean.getUniqueName()); + if (nList != null && !nList.isEmpty()) + { + nList.clear(); + } + } + else + { + // Clear the selected notifications + for (NotificationObject obj : list) + { + List<NotificationObject> nList = _notificationsMap.get(mbean.getUniqueName()); + if (nList != null && !nList.isEmpty()) + { + nList.remove(obj); + } + } + } + } + } + + + + /** + * Adds notification name and type to the map. The map contains all the notification names, + * subscribed for an mbean. + * @param mbean + * @param name + * @param type + */ + public void addNotificationListener(ManagedBean mbean, String name, String type) + { + // Get the subscribed notifications map for given mbean. If map is null then create a new one. + HashMap<String, List<String>> map = _subscribedNotificationMap.get(mbean.getUniqueName()); + if (map == null) + { + map = new HashMap<String, List<String>>(); + _subscribedNotificationMap.put(mbean.getUniqueName(),map); + } + + // Get the list of notification types for given notification name. If null, then create a new list. + List<String> list = map.get(name); + if (list == null) + { + list = new ArrayList<String>(); + map.put(name, list); + } + // Now add the notification type to the list + if (ALL.equals(type)) + { + List<NotificationInfoModel> infoList = _notificationInfoMap.get(mbean.getUniqueName()); + for (NotificationInfoModel model : infoList) + { + if (model.getName().equals(name)) + { + String[] types = model.getTypes(); + for (int i = 0; i < types.length; i++) + { + list.add(types[i]); + } + } + } + } + else + { + list.add(type); + } + + //System.out.println("Subscribed for notification :" + mbean.getUniqueName()); + } + + /** + * Checks if the given notification name and type are subscribed for the mbean. + */ + public boolean hasSubscribedForNotifications(ManagedBean mbean, String name, String type) + { + if (_subscribedNotificationMap.containsKey(mbean.getUniqueName())) + { + HashMap<String, List<String>> map = _subscribedNotificationMap.get(mbean.getUniqueName()); + if (map.containsKey(name)) + { + if (map.get(name).contains(type)) + { + return true; + } + } + } + return false; + } + + /** + * Clears the notification name and type information from the subscribed notifications map + * and removes the listener from mbeanserver connection + * @param mbean + * @param name + * @param type + * @throws Exception + */ + public void removeNotificationListener(ManagedBean mbean, String name, String type) throws Exception + { + //System.out.println("Removed notification listener :" + mbean.getUniqueName() + name +type); + if (_subscribedNotificationMap.containsKey(mbean.getUniqueName())) + { + // get the notifications map. This map contains the notification name mapped with the notification types + HashMap<String, List<String>> map = _subscribedNotificationMap.get(mbean.getUniqueName()); + if (map.containsKey(name)) + { + if (ALL.equals(type)) + { + map.remove(name); + } + else if (type != null) + { + map.get(name).remove(type); + if (map.get(name).isEmpty()) + { + map.remove(name); + } + } + } + if (map.size() == 0) + { + _subscribedNotificationMap.remove(mbean.getUniqueName()); + } + + JMXManagedObject jmxbean = (JMXManagedObject)mbean; + _mbsc.removeNotificationListener(jmxbean.getObjectName(), _notificationListener); + } + } + + /** + * When the mbean registration request is received from the mbean server, then the client listener + * can use this method. It will add the mbean to a list, which will be used to add the mbean to + * the registry and gui + * @param objName + */ + public void registerManagedObject(ObjectName objName) + { + JMXManagedObject managedObject = new JMXManagedObject(objName); + managedObject.setServer(getManagedServer()); + addManagedObject(managedObject); + } + + /** + * When mbean unregistration notification is received from the mbean server, then client listener + * can invoke this method. It will add the mbean to the list of mbeans to be removed from registry + * @param objName + */ + public void unregisterManagedObject(ObjectName objName) + { + ManagedBean mbean = _mbeansMap.get(objName.toString()); + // Check if mbean was not available in the map. It can happen if mbean unregistration + // notification is received and the mbean is not added in the map. + if (mbean != null) + { + removeManagedObject(mbean); + _mbeansToBeRemoved.add(mbean); + } + } + + public List<ManagedBean> getObjectsToBeRemoved() + { + if (_mbeansToBeRemoved.isEmpty()) + return null; + else + { + List<ManagedBean> list = new CopyOnWriteArrayList<ManagedBean>(_mbeansToBeRemoved); + _mbeansToBeRemoved.clear(); + return list; + } + } + + public void setAttributeModel(ManagedBean mbean, ManagedAttributeModel value) + { + _attributeModelMap.put(mbean.getUniqueName(), value); + } + + public ManagedAttributeModel getAttributeModel(ManagedBean mbean) + { + return _attributeModelMap.get(mbean.getUniqueName()); + } + + public void setOperationModel(ManagedBean mbean, OperationDataModel value) + { + _operationModelMap.put(mbean.getUniqueName(), value); + } + + public OperationDataModel getOperationModel(ManagedBean mbean) + { + return _operationModelMap.get(mbean.getUniqueName()); + } + + public List<String> getQueueNames(String virtualHostName) + { + List<ManagedBean> list = getQueues(virtualHostName); + if (list == null) + return null; + + List<String> queueNames = new ArrayList<String>(); + for (ManagedBean mbean : list) + { + queueNames.add(mbean.getName()); + } + return queueNames; + } + + public String[] getExchangeNames(String virtualHostName) + { + List<ManagedBean> list = getExchanges(virtualHostName); + if (list == null) + return null; + + String[] exchanges = new String[list.size()]; + int i = 0; + for (ManagedBean mbean : list) + { + exchanges[i++] = mbean.getName(); + } + return exchanges; + } + + public String[] getConnectionNames(String virtualHostName) + { + List<ManagedBean> list = getExchanges(virtualHostName); + if (list == null) + return null; + + String[] connections = new String[list.size()]; + int i = 0; + for (ManagedBean mbean : list) + { + connections[i++] = mbean.getName(); + } + return connections; + } + + public void setUserList(List<String> list) + { + _usersList = list; + Collections.sort(_usersList); + } + + public List<String> getUsernames() + { + return _usersList; + } + + public ClientNotificationListener getNotificationListener() + { + return _notificationListener; + } + + public ClientListener getClientListener() + { + return _clientListener; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java new file mode 100644 index 0000000000..6d6aa80f4d --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java @@ -0,0 +1,619 @@ +/* + * + * 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.jmx; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.InstanceNotFoundException; +import javax.management.JMException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.ReflectionException; + +import org.apache.qpid.management.common.mbeans.ServerInformation; +import org.apache.qpid.management.ui.ApiVersion; +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.Constants; +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.ManagedServer; +import org.apache.qpid.management.ui.exceptions.ManagementConsoleException; +import org.apache.qpid.management.ui.model.AttributeData; +import org.apache.qpid.management.ui.model.ManagedAttributeModel; +import org.apache.qpid.management.ui.model.NotificationInfoModel; +import org.apache.qpid.management.ui.model.OperationData; +import org.apache.qpid.management.ui.model.OperationDataModel; +import org.apache.qpid.management.ui.model.ParameterData; +import org.apache.qpid.management.ui.views.ViewUtility; + +/** + * Utility class for all mbeanserver related operations. Keeps all JMX code out from view and model classes + * @author Bhupendra Bhardwaj + */ +public class MBeanUtility +{ + public static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE); + public static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); + /** + * Retrieves the MBeanInfo from MBeanServer and stores in the application registry + * @param mbean managed bean + * @return MBeanInfo + * @throws Exception, if server connection is null or if server throws Exception + */ + public static MBeanInfo getMBeanInfo(ManagedBean mbean) throws Exception + { + ManagedServer server = mbean.getServer(); + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(server); + + MBeanServerConnection mbsc = serverRegistry.getServerConnection(); + if (mbsc == null) + { + throw new ManagementConsoleException("Server connection is broken"); + } + + JMXManagedObject jmxbean = (JMXManagedObject)mbean; + MBeanInfo mbeanInfo = mbsc.getMBeanInfo(jmxbean.getObjectName()); + serverRegistry.putMBeanInfo(mbean, mbeanInfo); + + // populate the server registry with attribute and operation info + getAttributes(mbean); + getOperations(mbean); + + return mbeanInfo; + } + + /** + * executes the MBean operation + * @param mbean + * @param opData + * @return MBean operation return value + * @throws Exception if server connection is broken or if operation execution fails on the mbean server + */ + public static Object execute(ManagedBean mbean, OperationData opData) throws Exception + { + String opName = opData.getName(); + Object[] values = null; + String[] signature = null; + + List<ParameterData> params = opData.getParameters(); + if (params != null && !params.isEmpty()) + { + signature = new String[params.size()];; + values = new Object[params.size()]; + for (int i = 0; i < params.size(); i++) + { + signature[i] = params.get(i).getType(); + values[i] = params.get(i).getValue(); + } + } + + ManagedServer server = mbean.getServer(); + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(server); + + MBeanServerConnection mbsc = serverRegistry.getServerConnection(); + if (mbsc == null) + { + throw new ManagementConsoleException("Server connection is broken"); + // TODO + // try and get the connection again if it was disconnected + } + JMXManagedObject jmxbean = (JMXManagedObject)mbean; + return mbsc.invoke(jmxbean.getObjectName(), opName, values, signature); + } + + /** + * @see MBeanUtility#handleException(ManagedBean, Exception) + */ + public static void handleException(Exception ex) + { + handleException(null, ex); + } + + /** + * handels the exception received. Shows the exception to the user in best suitable way + * @param mbean managed bean + * @param ex Exception + */ + public static void handleException(ManagedBean mbean, Throwable ex) + { + if (mbean == null) + { + ViewUtility.popupErrorMessage("Error", "Managed Object is null \n" + ex.toString()); + printStackTrace(ex); + } + else if (ex instanceof ReflectionException) + { + ViewUtility.popupErrorMessage(mbean.getInstanceName(), "Server has thrown error \n" + ex.toString()); + printStackTrace(ex); + } + else if (ex instanceof InstanceNotFoundException) + { + ViewUtility.popupErrorMessage(mbean.getInstanceName(), "Managed Object Not Found \n" + ex.toString()); + printStackTrace(ex); + } + else if (ex instanceof MBeanException) + { + String cause = ((MBeanException)ex).getTargetException().getMessage(); + if (cause == null) + cause = ex.toString(); + ViewUtility.popupInfoMessage(mbean.getInstanceName(), cause); + } + else if (ex instanceof JMException) + { + ViewUtility.popupErrorMessage(mbean.getInstanceName(), "Management Exception occured \n" + ex.toString()); + } + else if (ex instanceof ManagementConsoleException) + { + ViewUtility.popupErrorMessage(mbean.getInstanceName(), ex.getMessage()); + } + else if (ex instanceof SecurityException) + { + ViewUtility.popupErrorMessage(mbean.getInstanceName(), ex.getMessage()); + } + else + { + if (ex.getCause() != null) + { + handleException(mbean, ex.getCause()); + } + else + { + String msg = ex.getMessage(); + if (msg == null) + { + msg = ex.toString(); + } + ViewUtility.popupErrorMessage(mbean.getInstanceName(), msg); + printStackTrace(ex); + } + } + + } + + /** + * Registers the notification listener with the MBeanServer + * @param mbean managed bean + * @param name notification name + * @param type notification type + * @throws Exception if server connection is broken or if listener could not be created + */ + public static void createNotificationlistener(ManagedBean mbean, String name, String type) + throws Exception + { + JMXManagedObject jmxbean = (JMXManagedObject)mbean; + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean); + serverRegistry.addNotificationListener(mbean, name, type); + MBeanServerConnection mbsc = serverRegistry.getServerConnection(); + + if (mbsc == null) + { + throw new ManagementConsoleException("Server connection is broken"); + } + mbsc.addNotificationListener(jmxbean.getObjectName(), serverRegistry.getNotificationListener(), null, null); + } + + public static void removeNotificationListener(ManagedBean mbean, String name, String type) throws Exception + { + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean); + serverRegistry.removeNotificationListener(mbean, name, type); + } + + /** + * Checks if the server registry contains attribute information for this mbean. If not then it queries the + * mbean server for complete mbean information, else it gets the latest value of the given attribute + * from mbean server. + * @return attribute data for the given mbean attribute + */ + public static AttributeData getAttributeData(ManagedBean mbean, String attribute) throws Exception + { + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean); + ManagedAttributeModel attributeModel = serverRegistry.getAttributeModel(mbean); + if (attributeModel == null) + { + // If process is here, it means the mbeanInfo is not retrieved from mbean server even once for this mbean + getMBeanInfo(mbean); + } + else + { + // refresh attribute value from mbean server + refreshAttribute(mbean, attribute); + } + attributeModel = serverRegistry.getAttributeModel(mbean); + return attributeModel.getAttribute(attribute); + } + + /** + * Retrieves the latest attribute value from mbean server for the given mbean attribute + * and also sets that value in the attribute model in the server registry + * @return latest attribute value for the given mbean attribute + */ + public static Object refreshAttribute(ManagedBean mbean, String attribute) throws Exception + { + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean); + MBeanServerConnection mbsc = serverRegistry.getServerConnection(); + + if (mbsc == null) + { + throw new ManagementConsoleException("Server connection is broken"); + } + + Object value = mbsc.getAttribute(((JMXManagedObject)mbean).getObjectName(), attribute); + // update the attribute data in server registry for this attribute + ManagedAttributeModel attributeModel = serverRegistry.getAttributeModel(mbean); + attributeModel.setAttributeValue(attribute, value); + return value; + } + + + /** + * Returns a List of Object arrays containing the requested attribute values (in the same sequence requested) for each queue in the virtualhost. + * If a particular attribute cant be found or raises an mbean/reflection exception whilst being gathered its value is substituted with the String "-". + */ + public static List<List<Object>> getQueueAttributes(List<ManagedBean> mbeans, String[] attributes) + { + List<List<Object>> results = new ArrayList<List<Object>>(); + + MBeanServerConnection mbsc = null; + if(mbeans.isEmpty()) + { + return results; + } + else + { + ManagedBean mbean = mbeans.get(0); + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean); + mbsc = serverRegistry.getServerConnection(); + } + + if(mbsc == null) + { + return results; + } + + for(ManagedBean mbean : mbeans) + { + HashMap<String,Object> tempResults = new HashMap<String,Object>(); + + ObjectName objName = ((JMXManagedObject)mbean).getObjectName(); + try + { + AttributeList list = mbsc.getAttributes(objName, attributes); + + for (Attribute attr : list.toArray(new Attribute[0])) + { + tempResults.put(attr.getName(), attr.getValue()); + } + + List<Object> attributeValues = new ArrayList<Object>(attributes.length); + + for(int i = 0; i <attributes.length; i++) + { + if(tempResults.containsKey(attributes[i])) + { + attributeValues.add(tempResults.get(attributes[i])); + } + else + { + attributeValues.add("-"); + } + } + + results.add(attributeValues); + } + catch (Exception ignore) + { + continue; + } + } + + return results; + } + + + /** + * Retrieves the attribute values from MBeanSever and stores in the server registry. + * @param mbean + * @return the attribute model + * @throws Exception if attributes can not be retrieved from MBeanServer + */ + public static ManagedAttributeModel getAttributes(ManagedBean mbean) throws Exception + { + ObjectName objName = ((JMXManagedObject)mbean).getObjectName(); + String[] attributes = null; + AttributeList list = null; + + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean); + MBeanServerConnection mbsc = serverRegistry.getServerConnection(); + MBeanAttributeInfo[] attributesInfo = null; + ManagedAttributeModel attributeModel = serverRegistry.getAttributeModel(mbean); + + if (attributeModel == null) + { + // If the process is here, then it means the attribute values are not retrieved from mbean server + // even once for this mbean. Create attribute model, retrieve values from mbean server and + // set the attribute model in server registry for this mbean + attributeModel = new ManagedAttributeModel(); + attributesInfo = serverRegistry.getMBeanInfo(mbean).getAttributes(); + attributes = new String[attributesInfo.length]; + for (int i = 0; i< attributesInfo.length ; i++) + { + attributes[i] = attributesInfo[i].getName(); + attributeModel.setAttributeDescription(attributes[i], attributesInfo[i].getDescription()); + attributeModel.setAttributeWritable(attributes[i], attributesInfo[i].isWritable()); + attributeModel.setAttributeReadable(attributes[i], attributesInfo[i].isReadable()); + } + } + else + { + attributes = attributeModel.getAttributeNames().toArray(new String[0]); + } + + if (attributes.length != 0) + { + list = mbsc.getAttributes(objName, attributes); + for (Iterator itr = list.iterator(); itr.hasNext();) + { + Attribute attrib = (Attribute)itr.next(); + attributeModel.setAttributeValue(attrib.getName(), attrib.getValue()); + } + } + + serverRegistry.setAttributeModel(mbean, attributeModel); + return attributeModel; + } + + /** + * Updates the attribute value of an MBean + * @param mbean + * @param attribute + * @param value + * @throws Exception if MBeanServer throws exception in updating the attribute value + */ + public static void updateAttribute(ManagedBean mbean, AttributeData attribute, String value) throws Exception + { + JMXManagedObject jmxbean = (JMXManagedObject)mbean; + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean); + + MBeanServerConnection mbsc = serverRegistry.getServerConnection(); + + Object newValue = value; + if (attribute.getDataType().equals(Long.class.getName())) + { + if (MAX_LONG.compareTo(new BigInteger(value)) == -1) + { + throw new ManagementConsoleException("Entered value is too big for \"" + + ViewUtility.getDisplayText(attribute.getName()) + "\""); + } + newValue = Long.parseLong(value); + } + else if (attribute.getDataType().equals(Integer.class.getName())) + { + if (MAX_INT.compareTo(new BigInteger(value)) == -1) + { + throw new ManagementConsoleException("Entered value is too big for " + attribute.getName()); + } + newValue = Integer.parseInt(value); + } + else if (attribute.getDataType().equals(Boolean.class.getName())) + { + if (!value.equalsIgnoreCase("true") && !value.equalsIgnoreCase("false")) + { + throw new ManagementConsoleException("Entered value was not true or false"); + } + + newValue = Boolean.valueOf(value); + } + + mbsc.setAttribute(jmxbean.getObjectName(), new Attribute(attribute.getName(), newValue)); + // Update the value in the registry, to avoid refreshing from mbsc + ManagedAttributeModel attributeModel = serverRegistry.getAttributeModel(mbean); + attributeModel.setAttributeValue(attribute.getName(), newValue); + } + + /** + * populates the operation data model in server registry for given mbean + * @param mbean + * @return operation data model + */ + public static OperationDataModel getOperations(ManagedBean mbean) + { + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean); + OperationDataModel dataModel = serverRegistry.getOperationModel(mbean); + if (dataModel == null) + { + // Create operation model and set it in server registry for this mbean + MBeanOperationInfo[] operationsInfo = serverRegistry.getMBeanInfo(mbean).getOperations(); + dataModel = new OperationDataModel(); + + for (int i = 0; i < operationsInfo.length; i++) + { + dataModel.addOperation(operationsInfo[i]); + } + + serverRegistry.setOperationModel(mbean, dataModel); + } + return dataModel; + } + + /** + * populates the notification in the server registry for given mbean + * @param mbean + * @return notification info model + */ + public static NotificationInfoModel[] getNotificationInfo(ManagedBean mbean) + { + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(mbean); + MBeanNotificationInfo[] info = serverRegistry.getMBeanInfo(mbean).getNotifications(); + + // Check if this mbean sends any notification + if (info == null || info.length == 0) + return null; + + // Create notification model if not already set in the server registry for this mbean + List<NotificationInfoModel> list = serverRegistry.getNotificationInfo(mbean); + if (list != null) + return list.toArray(new NotificationInfoModel[0]); + else + list = new ArrayList<NotificationInfoModel>(); + + for (int i = 0; i < info.length; i++) + { + list.add(new NotificationInfoModel(info[i].getName(), info[i].getDescription(), info[i].getNotifTypes())); + } + + // Set the notification model in the server registry for this mbean + serverRegistry.setNotificationInfo(mbean, list); + return list.toArray(new NotificationInfoModel[0]); + } + + /** + * Retrieves all the MBeans from mbean server for a given domain + * @return list of ManagedBeans + */ + public static List<ManagedBean> getManagedObjectsForDomain(ManagedServer server, String domain) throws MalformedObjectNameException, NullPointerException, IOException + { + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(server); + return getManagedObjectsForDomain(server,serverRegistry, domain); + } + + /** + * Retrieves all the MBeans from mbean server for a given domain + * @return list of ManagedBeans + */ + public static List<ManagedBean> getManagedObjectsForDomain(ManagedServer server, JMXServerRegistry serverRegistry, String domain) throws MalformedObjectNameException, NullPointerException, IOException + { + List<ManagedBean> mbeans = new ArrayList<ManagedBean>(); + + MBeanServerConnection mbsc = serverRegistry.getServerConnection(); + ObjectName objName = new ObjectName(domain + ":*"); + Set objectInstances = mbsc.queryMBeans(objName, null); + + for (Iterator itr = objectInstances.iterator(); itr.hasNext();) + { + ObjectInstance instance = (ObjectInstance)itr.next(); + ManagedBean obj = new JMXManagedObject(instance.getObjectName()); + mbeans.add(obj); + } + + return mbeans; + } + + /** + * Classifies the management API version of the given server + * @return list of ManagedBeans + * @throws NullPointerException + * @throws ManagementConsoleException + * @throws MalformedObjectNameException + * @throws IOException + */ + public static void classifyManagementApiVersion(ManagedServer server, JMXServerRegistry serverRegistry) + throws MalformedObjectNameException, NullPointerException, IOException + { + MBeanServerConnection mbsc = serverRegistry.getServerConnection(); + + //Detect if the ServerInformation MBean is present, and use it to retrieve the API version. + ObjectName objName = new ObjectName(server.getDomain() + ":type="+ ServerInformation.TYPE + ",*"); + Set<ObjectName> objectInstances = mbsc.queryNames(objName, null); + + if(objectInstances.size() != 0) + { + for (Iterator<ObjectName> itr = objectInstances.iterator(); itr.hasNext();) + { + ObjectName instance = (ObjectName)itr.next(); + ServerInformation simb = (ServerInformation) + MBeanServerInvocationHandler.newProxyInstance(mbsc, + instance, ServerInformation.class, false); + + int major = simb.getManagementApiMajorVersion(); + int minor = simb.getManagementApiMinorVersion(); + + serverRegistry.setManagementApiVersion(new ApiVersion(major, minor)); + } + + return; + } + + //ServerInformation mbean was not present, so this is a older pre-v1.3 API server. + + //Detect the value of the 'version' key property on the UserManagement MBean ObjectName. + //If present, we have a v1.2 API server. If null, we have a v1.1 API server. + ObjectName umMBeanObjectName = null; + List<ManagedBean> mbeans = getManagedObjectsForDomain(server, serverRegistry, Constants.DEFAULT_DOMAIN); + for(ManagedBean mbean: mbeans) + { + if("UserManagement".equalsIgnoreCase(mbean.getType())) + { + umMBeanObjectName = ((JMXManagedObject) mbean).getObjectName(); + break; + } + } + + if(umMBeanObjectName != null) + { + //UserManagement MBean was present, determine if it has a version key + if(umMBeanObjectName.getKeyProperty("version") != null) + { + serverRegistry.setManagementApiVersion(new ApiVersion(1, 2)); + } + else + { + //no version key, + serverRegistry.setManagementApiVersion(new ApiVersion(1, 1)); + } + + return; + } + + //UserManagement MBean was not present, connected to an old server: classify as v1.0 API + serverRegistry.setManagementApiVersion(new ApiVersion(1, 0)); + } + + public static void printOutput(String statement) + { + if (ApplicationRegistry.debug) + { + System.out.println(statement); + } + } + + public static void printStackTrace(Throwable ex) + { + if (ApplicationRegistry.debug) + { + ex.printStackTrace(); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/AttributeData.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/AttributeData.java new file mode 100644 index 0000000000..ccd4cf8df8 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/AttributeData.java @@ -0,0 +1,96 @@ +/* + * + * 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.model; + +public class AttributeData +{ + String name = ""; + String description = ""; + String dataType = ""; + Object value = ""; + boolean readable = true; + boolean writable = false; + + + public String getDataType() + { + return dataType; + } + public void setDataType(String dataType) + { + this.dataType = dataType; + } + + public String getDescription() + { + return description; + } + public void setDescription(String description) + { + this.description = description; + } + + public String getName() + { + return name; + } + public void setName(String name) + { + this.name = name; + } + + public Object getValue() + { + return value; + } + public void setValue(Object value) + { + if (value != null) + this.value = value; + } + public boolean isReadable() + { + return readable; + } + public void setReadable(boolean readable) + { + this.readable = readable; + } + public boolean isWritable() + { + return writable; + } + public void setWritable(boolean writable) + { + this.writable = writable; + } + + public boolean isNumber() + { + if ("int".equals(dataType) || "java.lang.Integer".equals(dataType) || + "long".equals(dataType) || "java.lang.Long".equals(dataType) ) + { + return true; + } + else + return false; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ManagedAttributeModel.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ManagedAttributeModel.java new file mode 100644 index 0000000000..b3219f15ea --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ManagedAttributeModel.java @@ -0,0 +1,118 @@ +/* + * + * 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.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class ManagedAttributeModel +{ + HashMap<String, AttributeData> _attributeMap = new HashMap<String, AttributeData>(); + + public void setAttributeValue(String name, Object value) + { + if (value == null) + return; + + AttributeData data = null; + String dataType = value.getClass().getName(); + if (_attributeMap.containsKey(name)) + { + data = _attributeMap.get(name); + data.setValue(value); + } + else + { + data = new AttributeData(); + data.setName(name); + data.setValue(value); + _attributeMap.put(name, data); + } + data.setDataType(dataType); + } + + + public void setAttributeDescription(String name, String value) + { + if (_attributeMap.containsKey(name)) + { + _attributeMap.get(name).setDescription(value); + } + else + { + AttributeData data = new AttributeData(); + data.setName(name); + data.setDescription(value); + _attributeMap.put(name, data); + } + } + + public void setAttributeReadable(String name, boolean readable) + { + if (_attributeMap.containsKey(name)) + { + _attributeMap.get(name).setReadable(readable); + } + else + { + AttributeData data = new AttributeData(); + data.setName(name); + data.setReadable(readable); + _attributeMap.put(name, data); + } + } + + public void setAttributeWritable(String name, boolean writable) + { + if (_attributeMap.containsKey(name)) + { + _attributeMap.get(name).setWritable(writable); + } + else + { + AttributeData data = new AttributeData(); + data.setName(name); + data.setWritable(writable); + _attributeMap.put(name, data); + } + } + + public List<String> getAttributeNames() + { + return new ArrayList<String>(_attributeMap.keySet()); + } + + public AttributeData[] getAttributes() + { + return _attributeMap.values().toArray(new AttributeData[0]); + } + + public AttributeData getAttribute(String name) + { + return _attributeMap.get(name); + } + + public int getCount() + { + return _attributeMap.size(); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationInfoModel.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationInfoModel.java new file mode 100644 index 0000000000..6d4160889e --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationInfoModel.java @@ -0,0 +1,51 @@ +/* + * + * 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.model; + +public class NotificationInfoModel +{ + String name; + String description; + String[] types; + + public NotificationInfoModel(String name, String desc, String[] types) + { + this.name = name; + this.description = desc; + this.types = types; + } + + public String getDescription() + { + return description; + } + + public String getName() + { + return name; + } + + public String[] getTypes() + { + return types; + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java new file mode 100644 index 0000000000..35cc9f6e27 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java @@ -0,0 +1,132 @@ +/* + * + * 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.model; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import javax.management.ObjectName; + +import static org.apache.qpid.management.ui.Constants.VIRTUAL_HOST; + +public class NotificationObject +{ + + private long _sequenceNo; + private Date _timeStamp; + private String _message; + private Object _source; + private String _type; // INFO, WARN, etc + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss dd/MM/yy z"); + + public NotificationObject(long seqNo, Date timeStamp, String message, Object source, String type) + { + this._sequenceNo = seqNo; + this._message = message; + this._source = source; + this._type = type; + this._timeStamp = timeStamp; + dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + } + + public Object getSource() + { + return _source; + } + public void setSource(Object _source) + { + this._source = _source; + } + + public String getSourceName() + { + if (_source instanceof ObjectName) + { + return unquote(((ObjectName)_source).getKeyProperty("name")); + } + + return null; + } + + public String getSourceVirtualHost() + { + if (_source instanceof ObjectName) + { + return unquote(((ObjectName)_source).getKeyProperty(VIRTUAL_HOST)); + } + + return null; + } + + private String unquote(String value) + { + if(value != null) + { + try + { + //if the value is quoted in the ObjectName, unquote it + value = ObjectName.unquote(value); + } + catch(IllegalArgumentException e) + { + //ignore, this just means the value is not quoted + //and can be left unchanged + } + } + + return value; + } + + public String getMessage() + { + return _message; + } + public void setMessage(String _message) + { + this._message = _message; + } + public long getSequenceNo() + { + return _sequenceNo; + } + public void setSequenceNo(long no) + { + _sequenceNo = no; + } + public String getTimeStamp() + { + return dateFormat.format(_timeStamp); + } + public void setTimeStamp(Date stamp) + { + _timeStamp = stamp; + } + public String getType() + { + return _type; + } + public void setType(String _type) + { + this._type = _type; + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationData.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationData.java new file mode 100644 index 0000000000..bf3b730b3e --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationData.java @@ -0,0 +1,110 @@ +/* + * + * 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.model; + +import java.util.List; + +public class OperationData +{ + private String _name; + private String _description; + private String _returnType; + private int _impact; + private List<ParameterData> _parameters; + + public OperationData(String value) + { + this._name = value; + } + + public String getName() + { + return _name; + } + + public String getDescription() + { + return _description; + } + + public void setDescription(String description) + { + this._description = description; + } + + public List<ParameterData> getParameters() + { + return _parameters; + } + + public void setParameters(List<ParameterData> parameters) + { + this._parameters = parameters; + } + + public int getImpact() + { + return _impact; + } + + public void setImpact(int impact) + { + this._impact = impact; + } + + public String getReturnType() + { + return _returnType; + } + + public void setReturnType(String returnType) + { + this._returnType = returnType; + } + + public boolean isReturnTypeBoolean() + { + return (_returnType.equals("boolean") || _returnType.equals("java.lang.Boolean")); + } + + public boolean isReturnTypeVoid() + { + return (_returnType.equals("void") || _returnType.equals("java.lang.Void")); + } + + public Object getParameterValue(String paramName) + { + if (_parameters == null) + { + return null; + } + + for (int i = 0; i < _parameters.size(); i++) + { + if (paramName.equalsIgnoreCase(_parameters.get(i).getName())) + { + return _parameters.get(i).getValue(); + } + } + + return null; + } +}
\ No newline at end of file diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationDataModel.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationDataModel.java new file mode 100644 index 0000000000..96964a81ef --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationDataModel.java @@ -0,0 +1,72 @@ +/* + * + * 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.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; + +public class OperationDataModel +{ + HashMap<String, OperationData> _operationMap = new HashMap<String, OperationData>(); + + public void addOperation(MBeanOperationInfo opInfo) + { + OperationData opData = new OperationData(opInfo.getName()); + opData.setDescription(opInfo.getDescription()); + opData.setImpact(opInfo.getImpact()); + opData.setReturnType(opInfo.getReturnType()); + + int parametersCount = opInfo.getSignature().length; + if (parametersCount != 0) + { + List<ParameterData> paramList = new ArrayList<ParameterData>(); + for (int i = 0; i < parametersCount; i++) + { + MBeanParameterInfo paramInfo = opInfo.getSignature()[i]; + ParameterData param = new ParameterData(paramInfo.getName(), paramInfo.getDescription(), + paramInfo.getType()); + paramList.add(param); + } + opData.setParameters(paramList); + } + + _operationMap.put(opInfo.getName(), opData); + } + + public OperationData getOperation(String name) + { + return _operationMap.get(name); + } + + public List<OperationData> getOperations() + { + return new ArrayList<OperationData>(_operationMap.values()); + } + + public int getCount() + { + return _operationMap.size(); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ParameterData.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ParameterData.java new file mode 100644 index 0000000000..d12217c6eb --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/ParameterData.java @@ -0,0 +1,95 @@ +/* + * + * 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.model; + +/** + * Class representing an mbean operation parameter + * @author Bhupendra Bhardwaj + */ +public class ParameterData +{ + private String _name; + private String _description; + private String _type; + private Object _value; + + ParameterData(String name, String desc, String type) + { + this._name = name; + this._description = desc; + this._type = type; + setDefaultValue(); + } + + public String getDescription() + { + return _description; + } + + public String getName() + { + return _name; + } + + public String getType() + { + return _type; + } + + public Object getValue() + { + return _value; + } + + public void setValueFromString(String strValue) + { + if ("int".equals(_type)) + _value = Integer.parseInt(strValue); + else if (isBoolean()) + _value = Boolean.valueOf(strValue); + else if ("long".equals(_type)) + _value = Long.parseLong(strValue); + else + _value = strValue; + } + + public void setValue(Object value) + { + this._value = value; + } + + public boolean isBoolean() + { + return (_type.equals("boolean") || _type.equals("java.lang.Boolean")); + } + + public void setDefaultValue() + { + if (isBoolean()) + { + _value = Boolean.valueOf("false"); + } + else + { + _value = null; + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java new file mode 100644 index 0000000000..2b9f5042dc --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java @@ -0,0 +1,922 @@ +/* + * + * 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 org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.jmx.JMXServerRegistry; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.model.AttributeData; +import org.apache.qpid.management.ui.model.ManagedAttributeModel; +import org.eclipse.jface.viewers.IColorProvider; +import org.eclipse.jface.viewers.IFontProvider; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; + + +/** + * Creates controller composite for the attribute's tab. + * @author Bhupendra Bhardwaj + */ +public class AttributesTabControl extends TabControl +{ + private FormToolkit _toolkit; + private ScrolledForm _form; + private Table _table = null; + private TableViewer _tableViewer = null; + private int[] tableWidths = new int[] {275, 275}; + + private Composite _tableComposite = null; + private Composite _buttonsComposite = null; + + private DisposeListener tableDisposeListener = new DisposeListenerImpl(); + final Image image; + private Button _detailsButton = null; + private Button _editButton = null; + private Button _graphButton = null; + private boolean disableEditing = false; + + private static final String MAX_VALUE = "MaxValue"; + private static final String GRAPH_VALUES = "GraphValues"; + private int GRAPH_WIDTH = 700; + private int GRAPH_HEIGHT = 450; + private int GRAPH_ITEM_GAP = 100; + private int startX = 80; + private int startY = 60; + + public AttributesTabControl(TabFolder tabFolder) + { + super(tabFolder); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createScrolledForm(_tabFolder); + GridLayout gridLayout = new GridLayout(2, false); + gridLayout.marginWidth = 0; + gridLayout.marginHeight = 0; + _form.getBody().setLayout(gridLayout); + _tableComposite = _toolkit.createComposite(_form.getBody()); + _tableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + _tableComposite.setLayout(new GridLayout()); + _buttonsComposite = _toolkit.createComposite(_form.getBody()); + _buttonsComposite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, true)); + _buttonsComposite.setLayout(new GridLayout()); + + image = Display.getCurrent().getSystemImage(SWT.ICON_INFORMATION); + createWidgets(); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * Creates required widgets for Attribute's tab + */ + protected void createWidgets() + { + createTable(); + createTableViewer(); + createButtons(); + addTableListeners(); + } + + /** + * Creates table for listing the MBean attributes + */ + private void createTable() + { + _table = _toolkit.createTable(_tableComposite, SWT.FULL_SELECTION); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + _table.setLayoutData(gridData); + + for (int i = 0; i < ATTRIBUTE_TABLE_TITLES.size(); ++i) + { + final TableColumn column = new TableColumn(_table, SWT.NONE); + column.setText(ATTRIBUTE_TABLE_TITLES.get(i)); + column.setWidth(tableWidths[i]); + column.setResizable(true); + } + + _table.setLinesVisible (true); + _table.setHeaderVisible (true); + } + + /** + * Creates tableviewer for the attribute's table + */ + private void createTableViewer() + { + _tableViewer = new TableViewer(_table); + _tableViewer.setUseHashlookup(true); + _tableViewer.setColumnProperties( + ATTRIBUTE_TABLE_TITLES.toArray(new String[ATTRIBUTE_TABLE_TITLES.size()])); + _tableViewer.setContentProvider(new ContentProviderImpl()); + _tableViewer.setLabelProvider(new LabelProviderImpl()); + _tableViewer.setSorter(new ViewerSorterImpl()); + } + + private void createButtons() + { + addDetailsButton(); + addEditButton(); + addGraphButton(); + } + + private void addDetailsButton() + { + // Create and configure the button for attribute details + _detailsButton = _toolkit.createButton(_buttonsComposite, BUTTON_DETAILS, SWT.PUSH | SWT.CENTER); + _detailsButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false); + gridData.widthHint = 80; + _detailsButton.setLayoutData(gridData); + _detailsButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + disableEditing = true; + int index = _table.getSelectionIndex(); + TableItem item = _table.getItem(index); + createDetailsPopup((AttributeData)item.getData()); + disableEditing = false; + setFocus(); + } + }); + } + + /** + * Creates the button for editing attributes. + */ + private void addEditButton() + { + // Create and configure the button for editing attribute + _editButton = _toolkit.createButton(_buttonsComposite, BUTTON_EDIT_ATTRIBUTE, SWT.PUSH | SWT.CENTER); + _editButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false); + gridData.widthHint = 80; + _editButton.setLayoutData(gridData); + _editButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int index = _table.getSelectionIndex(); + TableItem item = _table.getItem(index); + createDetailsPopup((AttributeData)item.getData()); + setFocus(); + } + }); + } + + /** + * Creates the button for viewing Graphs + */ + private void addGraphButton() + { + _graphButton = _toolkit.createButton(_buttonsComposite, BUTTON_GRAPH, SWT.PUSH | SWT.CENTER); + _graphButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false); + gridData.widthHint = 80; + _graphButton.setLayoutData(gridData); + _graphButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent event) + { + int selectionIndex = _table.getSelectionIndex(); + AttributeData data = (AttributeData)_table.getItem(selectionIndex).getData(); + createGraph(data); + setFocus(); + } + }); + } + + private void addTableListeners() + { + _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + IStructuredSelection ss = (IStructuredSelection)evt.getSelection(); + checkForEnablingButtons((AttributeData)ss.getFirstElement()); + } + }); + + MouseListenerImpl listener = new MouseListenerImpl(); + _tableViewer.getTable().addMouseTrackListener(listener); + _tableViewer.getTable().addMouseMoveListener(listener); + _tableViewer.getTable().addMouseListener(listener); + + _table.addDisposeListener(tableDisposeListener); + + // _table is equal to _tableViewer.getControl() + _table.addListener(SWT.MeasureItem, new Listener() { + public void handleEvent(Event event) + { + event.height = event.gc.getFontMetrics().getHeight() * 3/2; + } + }); + } + + /** + * Listeners implementation class for showing table tooltip + * @author Bhupendra Bhardwaj + */ + private class MouseListenerImpl implements MouseTrackListener, MouseMoveListener, KeyListener, MouseListener + { + Shell tooltipShell = null; + Label tooltipLabel = null; + public void mouseHover(MouseEvent event) + { + TableItem item = _table.getItem (new Point (event.x, event.y)); + + if (item != null) + { + AttributeData data = (AttributeData)item.getData(); + if (tooltipShell != null && !tooltipShell.isDisposed ()) tooltipShell.dispose (); + tooltipShell = new Shell(_table.getShell(), SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL); + tooltipShell.setBackground(event.display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + FillLayout layout = new FillLayout(); + layout.marginWidth = 2; + tooltipShell.setLayout(layout); + tooltipLabel = new Label(tooltipShell, SWT.NONE); + tooltipLabel.setForeground(event.display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); + tooltipLabel.setBackground(event.display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + tooltipLabel.setText(data.getDescription()); + tooltipLabel.setData("_TABLEITEM", item); + tooltipLabel.addListener(SWT.MouseExit, tooltipLabelListener); + tooltipLabel.addListener(SWT.MouseDown, tooltipLabelListener); + Point size = tooltipShell.computeSize(SWT.DEFAULT, SWT.DEFAULT); + Rectangle rect = item.getBounds(0); + Point pt = _table.toDisplay(rect.x, rect.y); + tooltipShell.setBounds(pt.x, pt.y, size.x, size.y); + tooltipShell.setVisible(true); + } + } + public void mouseEnter(MouseEvent e) + { + } + public void mouseExit(MouseEvent e) + { + } + + // MouseMoveListener implementation + public void mouseMove(MouseEvent event) + { + if (tooltipShell == null) + return; + + tooltipShell.dispose(); + tooltipShell = null; + tooltipLabel = null; + } + + // KeyListener implementation + public void keyPressed(KeyEvent e) + { + if (tooltipShell == null) + return; + + tooltipShell.dispose(); + tooltipShell = null; + tooltipLabel = null; + } + public void keyReleased(KeyEvent e) + { + + } + + // MouseListener implementation + public void mouseDoubleClick(MouseEvent event) + { + if (tooltipShell != null) + { + tooltipShell.dispose(); + tooltipShell = null; + tooltipLabel = null; + } + Table table = (Table)event.getSource(); + int selectionIndex = table.getSelectionIndex(); + AttributeData data = (AttributeData)table.getItem(selectionIndex).getData(); + createDetailsPopup(data); + } + public void mouseDown(MouseEvent e) + { + if (tooltipShell != null) + { + tooltipShell.dispose(); + tooltipShell = null; + tooltipLabel = null; + } + } + public void mouseUp(MouseEvent e) + { + + } + } // end of MouseListenerImpl + + /** + * Creates pop-up window for showing attribute details + * @param data - Selectes attribute + */ + public void createDetailsPopup(AttributeData data) + { + int width = 500; + int height = 250; + if (!isSimpleType(data.getValue())) + { + width = 650; + height = 450; + } + + Display display = Display.getCurrent(); + Shell shell = ViewUtility.createPopupShell(ATTRIBUTE, width, height); + createDetailsPopupContents(shell, data); + + shell.open(); + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + { + display.sleep(); + } + } + shell.dispose(); + } + + /** + * Listener class for table tooltip label + */ + final Listener tooltipLabelListener = new Listener () + { + public void handleEvent (Event event) + { + Label label = (Label)event.widget; + Shell shell = label.getShell(); + switch (event.type) + { + case SWT.MouseDown: + Event e = new Event(); + e.item = (TableItem)label.getData ("_TABLEITEM"); + _table.setSelection(new TableItem[] {(TableItem)e.item}); + shell.dispose(); + _table.setFocus(); + break; + case SWT.MouseExit: + shell.dispose(); + break; + } + } + }; + + + /** + * Create the contents for the attribute details window pop-up + * @param shell - The shell that will be filled with details. + * @param attribute - Selected attribute + */ + private void createDetailsPopupContents(Composite shell, AttributeData attribute) + { + GridLayout layout = new GridLayout(2, false); + layout.horizontalSpacing = 10; + layout.verticalSpacing = 10; + layout.marginHeight = 20; + layout.marginWidth = 20; + + Composite parent = _toolkit.createComposite(shell, SWT.NONE); + parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + parent.setLayout(layout); + + // Name + Label label = _toolkit.createLabel(parent, ATTRIBUTE_TABLE_TITLES.get(0), SWT.NONE); + GridData layoutData = new GridData(SWT.TRAIL, SWT.TOP, false, false); + label.setLayoutData(layoutData); + int textStyle = SWT.BEGINNING | SWT.BORDER |SWT.READ_ONLY; + Text value = _toolkit.createText(parent, ViewUtility.getDisplayText(attribute.getName()), textStyle); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + + // Description + label = _toolkit.createLabel(parent, DESCRIPTION, SWT.NONE); + label.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); + value = _toolkit.createText(parent, attribute.getDescription(), textStyle); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + // value + label = _toolkit.createLabel(parent, ATTRIBUTE_TABLE_TITLES.get(1), SWT.NONE); + label.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); + + if (!attribute.isReadable()) + { + value = _toolkit.createText(parent, "", textStyle); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + } + else + { + if (!isSimpleType(attribute.getValue())) + { + if (attribute.getValue() instanceof String[]) + { + String result = ""; + for(String val : (String[]) attribute.getValue()){ + result = result.concat(val+ "; "); + } + value = _toolkit.createText(parent, "", textStyle); + + value.setText(result); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + } + else + { + Composite composite = new Composite(parent, SWT.BORDER); + composite.setLayout(new GridLayout()); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + ViewUtility.populateCompositeWithData(_toolkit, composite, attribute.getValue()); + } + } + else + { + if (attribute.isWritable()) + { + value = _toolkit.createText(parent, "", SWT.BEGINNING | SWT.BORDER); + if(attribute.isNumber()) + { + value.addVerifyListener(new NumberVerifyListener()); + } + + // set data to access in the listener + parent.setData(attribute); + } + else + { + value = _toolkit.createText(parent, "", textStyle); + } + + value.setText(attribute.getValue().toString()); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + } + } + + + // Update button + Button updateButton = addUpdateButton(parent); + updateButton.setData(value); + if (!attribute.isWritable()) + { + updateButton.setVisible(false); + } + + if (disableEditing) + { + value.setEditable(false); + updateButton.setVisible(false); + } + } + + /** + * Create the button for updating attributes. This should be enabled for writable attribute + */ + private Button addUpdateButton(Composite parent) + { + final Button updateButton = new Button(parent, SWT.PUSH | SWT.CENTER); + // set the data to access in the listener + parent.setData(BUTTON_UPDATE, updateButton); + + updateButton.setText(BUTTON_UPDATE); + GridData gridData = new GridData (SWT.CENTER, SWT.BOTTOM, true, true, 2, 1); + gridData.widthHint = 100; + updateButton.setLayoutData(gridData); + updateButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent event) + { + try + { + Button button = (Button)event.widget; + Text text = (Text)button.getData(); + AttributeData data = (AttributeData)button.getParent().getData(); + MBeanUtility.updateAttribute(_mbean, data, text.getText()); + button.getShell().close(); + refresh(_mbean); + } + catch (Exception ex) + { + MBeanUtility.handleException(_mbean, ex); + } + } + }); + + return updateButton; + } + + /** + * Refreshes the attribute tab by querying the mbean server for latest values + */ + @Override + public void refresh(ManagedBean mbean) + { + _mbean = mbean; + if (_mbean == null) + { + _tableViewer.setInput(null); + return; + } + ManagedAttributeModel attributesList = null; + try + { + attributesList = MBeanUtility.getAttributes(mbean); + } + catch(Exception ex) + { + MBeanUtility.handleException(_mbean, ex); + } + _tableViewer.setInput(attributesList); + checkForEnablingButtons(getSelectionAttribute()); + + _form.layout(true); + _form.getBody().layout(true, true); + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + _table.setFocus(); + } + + /** + * Checks which buttons are to be enabled or disabled. The graph button will be enabled only + * for readable number attributes. Editing is enabled for writeable attribtues. + * @param attribute + */ + private void checkForEnablingButtons(AttributeData attribute) + { + if (attribute == null) + { + _detailsButton.setEnabled(false); + _editButton.setEnabled(false); + _graphButton.setEnabled(false); + return; + } + + _detailsButton.setEnabled(true); + if (attribute.isWritable()) + { + _editButton.setEnabled(true); + _graphButton.setEnabled(false); + } + else + { + _editButton.setEnabled(false); + // Currently only Queues are having attributes, which are suitable for a graph + if (attribute.isNumber() && _mbean.isQueue()) + { + _graphButton.setEnabled(true); + } + else + { + _graphButton.setEnabled(false); + } + } + } + + /** + * Creates graph in a pop-up window for given attribute. + * @param data + */ + private void createGraph(final AttributeData data) + { + Display display = Display.getCurrent(); + Shell shell = new Shell(display, SWT.BORDER | SWT.CLOSE | SWT.MIN | SWT.MAX); + shell.setText(_mbean.getName()); + int x = display.getBounds().width; + int y = display.getBounds().height; + shell.setBounds(x/4, y/4, GRAPH_WIDTH, GRAPH_HEIGHT); + shell.setLayout(new FillLayout()); + + final Canvas canvas = new Canvas(shell, SWT.NONE); + long currentValue = Long.parseLong(data.getValue().toString()); + long mValue = getGraphMaxValue(currentValue); + canvas.setData(MAX_VALUE, mValue); + canvas.setData(GRAPH_VALUES, new long[] {0,0,0,0,0,currentValue}); + + canvas.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); + canvas.addPaintListener(new PaintListener() + { + public void paintControl(PaintEvent event) + { + Canvas canvas = (Canvas)event.widget; + int maxX = canvas.getSize().x; + int maxY = canvas.getSize().y; + event.gc.fillRectangle(canvas.getBounds()); + event.gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK)); + event.gc.setLineWidth(4); + + Object canvasData = canvas.getData(MAX_VALUE); + String str = canvasData.toString(); + long maxValue = Long.parseLong(str); + // Set the graph dimensions + event.gc.drawText("0", startX - 40, maxY - startY - 10); + event.gc.drawText("" + maxValue/2, startX - 40, maxY/2); + event.gc.drawText("" + maxValue, startX - 40, startY); + + // horizontal line + event.gc.drawLine(startX, maxY - startY, maxX - 60, maxY - startY); + // vertical line + event.gc.drawLine(startX, maxY - startY, startX, startY); + // set graph text + event.gc.drawText(data.getName(), startX - 40, startY - 40); + event.gc.drawText("25 sec", startX, maxY - startY + 10); + event.gc.drawText("20 sec", startX + GRAPH_ITEM_GAP, maxY - startY + 10); + event.gc.drawText("15 sec", startX + GRAPH_ITEM_GAP * 2, maxY - startY + 10); + event.gc.drawText("10 sec", startX + GRAPH_ITEM_GAP * 3, maxY - startY + 10); + event.gc.drawText(" 5 sec", startX + GRAPH_ITEM_GAP * 4, maxY - startY + 10); + event.gc.drawText(" 0 sec", startX + GRAPH_ITEM_GAP * 5, maxY - startY + 10); + + // plot the graph now for values + event.gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)); + canvasData = canvas.getData(GRAPH_VALUES); + long[] graphValues = (long[]) canvasData; + for (int i = 0; i < graphValues.length; i++) + { + int x = startX + i * GRAPH_ITEM_GAP; + int yTotalLength = (maxY - 2 * startY); + float ratio = ((float)graphValues[i]/(float)maxValue); + int itemlength = (int)(yTotalLength * ratio); + int y = maxY - startY - itemlength; + event.gc.drawLine(x, maxY- startY, x, y); + event.gc.drawText(String.valueOf(graphValues[i]), x, y - 20); + } + } + }); + + shell.open(); + + // Set up the timer for the animation + Runnable runnable = new Runnable() + { + public void run() + { + try + { + animate(canvas, data); + Display.getCurrent().timerExec(TIMER_INTERVAL, this); + } + catch(Exception ex) + { + MBeanUtility.handleException(ex); + } + } + }; + + // Launch the timer + display.timerExec(TIMER_INTERVAL, runnable); + + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + { + display.sleep(); + } + } + + // Kill the timer + display.timerExec(-1, runnable); + shell.dispose(); + } + + /** + * @return selected attribute in the table + */ + public AttributeData getSelectionAttribute() + { + int index = _table.getSelectionIndex(); + if (index == -1) + return null; + + return (AttributeData)_table.getItem(index).getData(); + } + + /** + * checks for newer values of selected attribute to update the graph + * @param canvas + * @param data + * @throws Exception + */ + private void animate(Canvas canvas, AttributeData data) throws Exception + { + String attribute = data.getName(); + Object valueObj = MBeanUtility.refreshAttribute(_mbean, attribute); + int value = Integer.parseInt(String.valueOf(valueObj)); + Object canvasData = canvas.getData(GRAPH_VALUES); + long[] graphValues = (long[]) canvasData; + + for (int i = 0; i < graphValues.length -1; i++) + { + graphValues[i] = graphValues[i + 1]; + } + graphValues[graphValues.length - 1] = value; + + canvasData = canvas.getData(MAX_VALUE); + long maxValue = Long.parseLong(String.valueOf(canvasData)); + if (maxValue < value) + { + maxValue = getGraphMaxValue(value); + canvas.setData(MAX_VALUE, maxValue); + } + + canvas.redraw(); + } + + /** + * @param maxAttributeValue + * @return dynamically calculated value for y-axis on the graph + */ + private long getGraphMaxValue(long maxAttributeValue) + { + long maxGraphValue = 100; + long temp = maxAttributeValue * 3/2; + if (temp > maxGraphValue) + { + long modulus = temp % 100; + maxGraphValue = temp + ( 100 - modulus); + } + + return maxGraphValue; + } + + /** + * Content Provider class for the table viewer + * @author Bhupendra Bhardwaj + */ + private static class ContentProviderImpl implements IStructuredContentProvider + { + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + public Object[] getElements(Object parent) + { + return ((ManagedAttributeModel)parent).getAttributes(); + } + } + + /** + * Label Provider class for the table viewer + * @author Bhupendra Bhardwaj + */ + private class LabelProviderImpl extends LabelProvider implements ITableLabelProvider, + IFontProvider, + IColorProvider + { + AttributeData attribute = null; + public String getColumnText(Object element, int columnIndex) + { + String result = ""; + attribute = (AttributeData) element; + + switch (columnIndex) + { + case 0 : // attribute name column + result = ViewUtility.getDisplayText(attribute.getName()); + break; + case 1 : // attribute value column + if (attribute.getValue() != null) + if (attribute.getValue() instanceof String[]) + { + for(String val : (String[]) attribute.getValue()){ + result = result.concat(val+ "; "); + } + } + else + { + result = String.valueOf(attribute.getValue()); + } + break; + default : + result = ""; + } + + return result; + } + + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + public Font getFont(Object element) + { + return ApplicationRegistry.getFont(FONT_TABLE_CELL); + } + + public Color getForeground(Object element) + { + attribute = (AttributeData) element; + if (attribute.isWritable()) + return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE); + else + return Display.getCurrent().getSystemColor(SWT.COLOR_BLACK); + } + public Color getBackground(Object element) + { + return _form.getBackground(); + } + } + + private static class DisposeListenerImpl implements DisposeListener + { + public void widgetDisposed(DisposeEvent e) + { + + } + } + + /** + * Sorter class for the table viewer. It sorts the table for according to attribute name. + * @author Bhupendra Bhardwaj + * + */ + private static class ViewerSorterImpl extends ViewerSorter + { + public int compare(Viewer viewer, Object o1, Object o2) + { + AttributeData attribtue1 = (AttributeData)o1; + AttributeData attribtue2 = (AttributeData)o2; + + return collator.compare(attribtue1.getName(), attribtue2.getName()); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/INotificationViewer.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/INotificationViewer.java new file mode 100644 index 0000000000..bc560b6064 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/INotificationViewer.java @@ -0,0 +1,32 @@ +/* + * + * 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 java.util.List; + +import org.apache.qpid.management.ui.model.NotificationObject; + +public interface INotificationViewer +{ + public void addNotification(NotificationObject notification); + + public void addNotification(List<NotificationObject> notificationList); +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java new file mode 100644 index 0000000000..527fc67be3 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanTabFolderFactory.java @@ -0,0 +1,466 @@ +/* + * + * 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.ATTRIBUTES; +import static org.apache.qpid.management.ui.Constants.CONNECTION; +import static org.apache.qpid.management.ui.Constants.EXCHANGE; +import static org.apache.qpid.management.ui.Constants.EXCHANGE_TYPE; +import static org.apache.qpid.management.ui.Constants.NOTIFICATIONS; +import static org.apache.qpid.management.ui.Constants.QUEUE; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; + +import javax.management.MBeanServerConnection; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ManagedServer; +import org.apache.qpid.management.ui.ServerRegistry; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.model.NotificationInfoModel; +import org.apache.qpid.management.ui.model.OperationData; +import org.apache.qpid.management.ui.model.OperationDataModel; +import org.apache.qpid.management.ui.views.queue.QueueOperationsTabControl; +import org.apache.qpid.management.ui.views.type.ConnectionTypeTabControl; +import org.apache.qpid.management.ui.views.type.ExchangeTypeTabControl; +import org.apache.qpid.management.ui.views.type.QueueTypeTabControl; +import org.apache.qpid.management.ui.views.users.UserManagementTabControl; +import org.apache.qpid.management.ui.views.vhost.VHostTabControl; +import org.apache.qpid.management.ui.views.connection.ConnectionOperationsTabControl; +import org.apache.qpid.management.ui.views.exchange.ExchangeOperationsTabControl; +import org.apache.qpid.management.ui.views.exchange.HeadersExchangeOperationsTabControl; +import org.apache.qpid.management.ui.views.logging.ConfigurationFileTabControl; +import org.apache.qpid.management.ui.views.logging.RuntimeTabControl; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; + +public class MBeanTabFolderFactory +{ + private static final String MBEANTYPE_QUEUE = "VirtualHost.Queue"; + private static final String MBEANTYPE_CONNECTION = "VirtualHost.Connection"; + private static final String MBEANTYPE_EXCHANGE = "VirtualHost.Exchange"; + private static final String MBEANTYPE_VHOST_MANAGER = "VirtualHost.VirtualHostManager"; + private static final String MBEANTYPE_LOGGING_MANAGEMENT = "LoggingManagement"; + private static final String MBEANTYPE_USER_MANAGEMENT = "UserManagement"; + private static final String MBEANTYPE_CONFIGURATION_MANAGEMENT = "ConfigurationManagement"; + + private MBeanTabFolderFactory() + { + //no instances + } + + public static TabFolder generateMBeanTabFolder(final Composite parent, final JMXManagedObject mbean, final MBeanServerConnection mbsc) + { + TabFolder tabFolder = new TabFolder(parent, SWT.NONE); + FormData layoutData = new FormData(); + layoutData.left = new FormAttachment(0); + layoutData.top = new FormAttachment(0); + layoutData.right = new FormAttachment(100); + layoutData.bottom = new FormAttachment(100); + tabFolder.setLayoutData(layoutData); + + TabItem tab; + TabControl controller; + QpidMBeanType mbeanType = QpidMBeanType.get(mbean.getType()); + + switch(mbeanType) + { + case QUEUE: + createAttributesTab(tabFolder, mbean); + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText("Operations"); + controller = new QueueOperationsTabControl(tabFolder, mbean, mbsc); + tab.setControl(controller.getControl()); + tab.setData(TabControl.CONTROLLER, controller); + break; + case CONNECTION: + createAttributesTab(tabFolder, mbean); + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText("Operations"); + controller = new ConnectionOperationsTabControl(tabFolder, mbean, mbsc); + tab.setControl(controller.getControl()); + tab.setData(TabControl.CONTROLLER, controller); + break; + case EXCHANGE: + createAttributesTab(tabFolder, mbean); + + if (mbean.getProperty(EXCHANGE_TYPE).equalsIgnoreCase("headers")) + { + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText("Operations"); + controller = new HeadersExchangeOperationsTabControl(tabFolder, mbean, mbsc); + tab.setControl(controller.getControl()); + tab.setData(TabControl.CONTROLLER, controller); + } + else + { + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText("Operations"); + controller = new ExchangeOperationsTabControl(tabFolder, mbean, mbsc); + tab.setControl(controller.getControl()); + tab.setData(TabControl.CONTROLLER, controller); + } + break; + case VHOST_MANAGER: + createAttributesTab(tabFolder, mbean); + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText("Operations"); + controller = new VHostTabControl(tabFolder, mbean, mbsc); + tab.setControl(controller.getControl()); + tab.setData(TabControl.CONTROLLER, controller); + break; + case LOGGING_MANAGEMENT: + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText("Runtime Options"); + controller = new RuntimeTabControl(tabFolder, mbean, mbsc); + tab.setControl(controller.getControl()); + tab.setData(TabControl.CONTROLLER, controller); + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText("ConfigurationFile Options"); + controller = new ConfigurationFileTabControl(tabFolder, mbean, mbsc); + tab.setControl(controller.getControl()); + tab.setData(TabControl.CONTROLLER, controller); + break; + case USER_MANAGEMENT: + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText("Operations"); + controller = new UserManagementTabControl(tabFolder, mbean, mbsc); + tab.setControl(controller.getControl()); + tab.setData(TabControl.CONTROLLER, controller); + break; + case CONFIGURATION_MANAGEMENT: + createGenericTabFolder(tabFolder, mbean); + break; + case UNKNOWN: + createGenericTabFolder(tabFolder, mbean); + break; + } + + createNotificationsTabIfNecessary(tabFolder, mbean); + + tabFolder.addListener(SWT.Selection, new Listener() + { + public void handleEvent(Event evt) + { + TabItem tab = (TabItem)evt.item; + TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER); + if(controller != null) + { + controller.refresh(mbean); + } + } + }); + + return tabFolder; + } + + private static void createGenericTabFolder(TabFolder tabFolder, JMXManagedObject mbean) + { + createAttributesTab(tabFolder, mbean); + createOperationTabs(tabFolder, mbean); + } + + private static void createAttributesTab(TabFolder tabFolder, JMXManagedObject mbean) + { + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(mbean); + if(serverRegistry.getAttributeModel(mbean).getCount() == 0) + { + return; + } + + TabItem tab = new TabItem(tabFolder, SWT.NONE); + tab.setText(ATTRIBUTES); + AttributesTabControl controller = new AttributesTabControl(tabFolder); + tab.setControl(controller.getControl()); + tab.setData(TabControl.CONTROLLER, controller); + } + + private static void createOperationTabs(TabFolder tabFolder, JMXManagedObject mbean) + { + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(mbean); + int operationsCount = serverRegistry.getOperationModel(mbean).getCount(); + if(operationsCount == 0) + { + return; + } + + OperationDataModel operationModel = serverRegistry.getOperationModel(mbean); + for(OperationData operationData : operationModel.getOperations()) + { + TabItem operationTab = new TabItem(tabFolder, SWT.NONE); + operationTab.setText(ViewUtility.getDisplayText(operationData.getName())); + operationTab.setData(operationData); + OperationTabControl control = new OperationTabControl(tabFolder, operationData); + operationTab.setData(TabControl.CONTROLLER, control); + operationTab.setControl(control.getControl()); + } + } + + private static void createNotificationsTabIfNecessary(TabFolder tabFolder, JMXManagedObject mbean) + { + NotificationInfoModel[] items = MBeanUtility.getNotificationInfo(mbean); + if(items == null || items.length == 0) + { + //the mbean has no notifications to subscribe for, do not create the tab. + return; + } + + NotificationsTabControl controller = new NotificationsTabControl(tabFolder, mbean); + + TabItem tab = new TabItem(tabFolder, SWT.NONE); + tab.setText(NOTIFICATIONS); + tab.setData(TabControl.CONTROLLER, controller); + tab.setControl(controller.getControl()); + } + + /** + * Creates TabFolder and tabs for all mbeantype (Connection, Queue, and Exchange) + */ + public static TabFolder generateMBeanTypeTabFolder(final Composite parent, ManagedServer server, String virtualHost) + { + TabFolder tabFolder = new TabFolder(parent, SWT.NONE); + FormData layoutData = new FormData(); + layoutData.left = new FormAttachment(0); + layoutData.top = new FormAttachment(0); + layoutData.right = new FormAttachment(100); + layoutData.bottom = new FormAttachment(100); + tabFolder.setLayoutData(layoutData); + + + TabItem tab; + TabControl controller; + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText(CONNECTION); + controller = new ConnectionTypeTabControl(tabFolder,server,virtualHost); + tab.setData(TabControl.CONTROLLER, controller); + tab.setControl(controller.getControl()); + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText(EXCHANGE); + controller = new ExchangeTypeTabControl(tabFolder,server,virtualHost); + tab.setData(TabControl.CONTROLLER, controller); + tab.setControl(controller.getControl()); + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText(QUEUE); + controller = new QueueTypeTabControl(tabFolder,server,virtualHost); + tab.setData(TabControl.CONTROLLER, controller); + tab.setControl(controller.getControl()); + + tabFolder.addListener(SWT.Selection, new Listener() + { + public void handleEvent(Event evt) + { + TabItem tab = (TabItem)evt.item; + TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER); + if(controller != null) + { + controller.refresh(null); + } + } + }); + + return tabFolder; + } + + /** + * Creates TabFolder and tab for the Connection selection view + */ + public static TabFolder generateConnectionTypeTabFolder(final Composite parent, ManagedServer server, String virtualHost) + { + TabFolder tabFolder = new TabFolder(parent, SWT.NONE); + FormData layoutData = new FormData(); + layoutData.left = new FormAttachment(0); + layoutData.top = new FormAttachment(0); + layoutData.right = new FormAttachment(100); + layoutData.bottom = new FormAttachment(100); + tabFolder.setLayoutData(layoutData); + + TabItem tab; + TabControl controller; + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText(CONNECTION); + controller = new ConnectionTypeTabControl(tabFolder,server,virtualHost); + tab.setData(TabControl.CONTROLLER, controller); + tab.setControl(controller.getControl()); + + tabFolder.addListener(SWT.Selection, new Listener() + { + public void handleEvent(Event evt) + { + TabItem tab = (TabItem)evt.item; + TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER); + if(controller != null) + { + controller.refresh(null); + } + } + }); + + return tabFolder; + } + + /** + * Creates TabFolder and tab for the Exchange selection view + */ + public static TabFolder generateExchangeTypeTabFolder(final Composite parent, ManagedServer server, String virtualHost) + { + TabFolder tabFolder = new TabFolder(parent, SWT.NONE); + FormData layoutData = new FormData(); + layoutData.left = new FormAttachment(0); + layoutData.top = new FormAttachment(0); + layoutData.right = new FormAttachment(100); + layoutData.bottom = new FormAttachment(100); + tabFolder.setLayoutData(layoutData); + + TabItem tab; + TabControl controller; + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText(EXCHANGE); + controller = new ExchangeTypeTabControl(tabFolder,server,virtualHost); + tab.setData(TabControl.CONTROLLER, controller); + tab.setControl(controller.getControl()); + + tabFolder.addListener(SWT.Selection, new Listener() + { + public void handleEvent(Event evt) + { + TabItem tab = (TabItem)evt.item; + TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER); + if(controller != null) + { + controller.refresh(null); + } + } + }); + + return tabFolder; + } + + /** + * Creates TabFolder and tab for the Queue selection view + */ + public static TabFolder generateQueueTypeTabFolder(final Composite parent, ManagedServer server, String virtualHost) + { + TabFolder tabFolder = new TabFolder(parent, SWT.NONE); + FormData layoutData = new FormData(); + layoutData.left = new FormAttachment(0); + layoutData.top = new FormAttachment(0); + layoutData.right = new FormAttachment(100); + layoutData.bottom = new FormAttachment(100); + tabFolder.setLayoutData(layoutData); + + TabItem tab; + TabControl controller; + + tab = new TabItem(tabFolder, SWT.NONE); + tab.setText(QUEUE); + controller = new QueueTypeTabControl(tabFolder,server,virtualHost); + tab.setData(TabControl.CONTROLLER, controller); + tab.setControl(controller.getControl()); + + tabFolder.addListener(SWT.Selection, new Listener() + { + public void handleEvent(Event evt) + { + TabItem tab = (TabItem)evt.item; + TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER); + if(controller != null) + { + controller.refresh(null); + } + } + }); + + return tabFolder; + } + + private enum QpidMBeanType + { + QUEUE (MBEANTYPE_QUEUE), + CONNECTION (MBEANTYPE_CONNECTION), + EXCHANGE (MBEANTYPE_EXCHANGE), + VHOST_MANAGER (MBEANTYPE_VHOST_MANAGER), + LOGGING_MANAGEMENT (MBEANTYPE_LOGGING_MANAGEMENT), + USER_MANAGEMENT (MBEANTYPE_USER_MANAGEMENT), + CONFIGURATION_MANAGEMENT (MBEANTYPE_CONFIGURATION_MANAGEMENT), + UNKNOWN (null); + + private static final Map<String,QpidMBeanType> lookup = new HashMap<String,QpidMBeanType>(); + + static + { + for(QpidMBeanType m : EnumSet.allOf(QpidMBeanType.class)) + { + lookup.put(m.getType(), m); + } + } + + private String type; + + private QpidMBeanType() + { + + } + + private QpidMBeanType(String type) + { + this.type = type; + } + + public String getType() + { + return type; + } + + public static QpidMBeanType get(String type) + { + QpidMBeanType t= lookup.get(type); + if (t != null) + { + return t; + } + else + { + return UNKNOWN; + } + + } + } + + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java new file mode 100644 index 0000000000..65615a6d18 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java @@ -0,0 +1,605 @@ +/* + * + * 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 java.util.LinkedList; + +import javax.management.MBeanServerConnection; + +import static org.apache.qpid.management.ui.Constants.*; + +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.ManagedServer; +import org.apache.qpid.management.ui.ServerRegistry; +import org.apache.qpid.management.ui.actions.BackAction; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.JMXServerRegistry; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.forms.widgets.Form; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.part.ViewPart; + +/** + * MBean View create appropriate view based on the user selection on the Navigation View. + */ +public class MBeanView extends ViewPart +{ + public static final String ID = "org.apache.qpid.management.ui.mbeanView"; + + private FormToolkit _toolkit = null; + private Form _form = null; + private String _formText = APPLICATION_NAME; + private static ManagedServer _server = null; + private TreeObject _selectedNode = null; + private ManagedBean _mbean = null; + private static String _virtualHostName = null; + private static MBeanServerConnection _mbsc = null; + private TabFolder _tabFolder = null; + private ISelectionListener _selectionListener = new SelectionListenerImpl(); + + // TabFolder to list all the mbeans for a given mbeantype(eg Connection, Queue, Exchange) + private TabFolder _typeTabFolder = null; + + private TabFolder _notificationTabFolder = null; + + private LinkedList<Object> _backHistory; + private BackAction _backAction; + + /* + * Listener for the selection events in the navigation view + */ + private class SelectionListenerImpl implements ISelectionListener + { + public void selectionChanged(IWorkbenchPart part, ISelection sel) + { + if (!(sel instanceof IStructuredSelection)) + return; + + IStructuredSelection ss = (IStructuredSelection) sel; + _selectedNode = (TreeObject)ss.getFirstElement(); + + + // mbean should be set to null. A selection done on the navigation view can be either an mbean or + // an mbeantype. For mbeantype selection(eg Connection, Queue, Exchange) _mbean will remain null. + _mbean = null; + clearView(); + + //clear the back history, it is only for use when opening subsequent mbeans not in the nav tree + _backHistory.clear(); + _backAction.setEnabled(false); + + // If a selected node(mbean) gets unregistered from mbean server, mbeanview should + // make the tabfolber for that mbean invisible + if (_selectedNode == null) + { + return; + } + + setServer(); + + if(!ApplicationRegistry.isServerConnected(_server)) + { + return; + } + + if (MBEAN.equals(_selectedNode.getType())) + { + _mbean = (ManagedBean)_selectedNode.getManagedObject(); + } + + setFormTitle(); + showRelevantTabView(); + } + } + + public void openMBean(ManagedBean mbean) + { + openMBean(mbean, false); + } + + private void openMBean(ManagedBean mbean, boolean undoing) + { + if(mbean == null) + { + return; + } + + //if an mbean is about to be opened (but not returning to using back) from the mbean view, + //then record the current viewed area/object as a means of back history + if(!undoing) + { + if(_backHistory.isEmpty()) + { + //ensure the button is enabled if this is to be the first history item + _backAction.setEnabled(true); + } + + if(_mbean == null) + { + //queue etc selection area is open, record the tree object + _backHistory.addLast(_selectedNode); + } + else + { + _backHistory.addLast(_mbean); + } + } + + _mbean = mbean; + + try + { + clearView(); + + setFormTitle(); + showMBean(mbean); + + _form.layout(true); + _form.getBody().layout(true, true); + } + catch(Exception ex) + { + MBeanUtility.handleException(mbean, ex); + } + } + + private void setFormTitle() + { + if (_mbean != null) + { + _formText = _mbean.getType(); + if ((_mbean.getVirtualHostName() != null) && (!DEFAULT_VH.equals(_mbean.getVirtualHostName())) ) + { + _formText = _formText.replaceFirst(VIRTUAL_HOST, _mbean.getVirtualHostName()); + if (_mbean.getName() != null && _mbean.getName().length() != 0) + { + _formText = _formText + ": " + _mbean.getName(); + } + } + } + else if ((_selectedNode.getVirtualHost() != null) && (!DEFAULT_VH.equals(_selectedNode.getVirtualHost()))) + { + _formText = _selectedNode.getVirtualHost(); + } + else + { + _formText = APPLICATION_NAME; + } + _form.setText(_formText); + } + + public void showRelevantTabView() + { + try + { + if (_selectedNode == null) + { + return; + } + + String mbeanType = _selectedNode.getType(); + + if (NODE_TYPE_TYPEINSTANCE.equals(mbeanType)) + { + // An virtual host instance is selected + generateTypeTabFolder(); + } + else if (NODE_TYPE_MBEANTYPE.equals(mbeanType)) + { + showTypeTabFolder(_selectedNode.getName()); + } + else if (NOTIFICATIONS.equals(mbeanType)) + { + refreshNotificationPage(); + } + else if (MBEAN.equals(mbeanType)) + { + showMBean(_mbean); + } + else if(NODE_TYPE_SERVER.equals(mbeanType)) + { + ServerRegistry serverReg = ApplicationRegistry.getServerRegistry(_server); + + //check the server is connected + if(serverReg != null) + { + //post a message if the server supports a newer API version. + ApiVersion serverAPI = serverReg.getManagementApiVersion(); + int supportedMajor = ApplicationRegistry.SUPPORTED_QPID_JMX_API_MAJOR_VERSION; + int supportedMinor = ApplicationRegistry.SUPPORTED_QPID_JMX_API_MINOR_VERSION; + + if(serverAPI.greaterThan(supportedMajor, supportedMinor)) + { + _form.setText("The server supports an updated management API and may offer " + + "functionality not available with this console. " + + "Please check for an updated console release."); + } + + } + } + else + { + return; + } + + _form.layout(true); + _form.getBody().layout(true, true); + } + catch(Exception ex) + { + MBeanUtility.handleException(_mbean, ex); + } + } + + /** + * Sets the managedServer based on the selection in the navigation view + * At any given time MBeanView will be displaying information for an mbean of mbeantype + * for a specifiv managed server. This server information will be used by the tab controllers + * to get server registry. + */ + private void setServer() + { + if (NODE_TYPE_SERVER.equals(_selectedNode.getType())) + { + _server = (ManagedServer)_selectedNode.getManagedObject(); + _virtualHostName = null; + } + else + { + TreeObject parent = _selectedNode.getParent(); + while (parent != null && !parent.getType().equals(NODE_TYPE_SERVER)) + { + parent = parent.getParent(); + } + + if (parent != null && parent.getType().equals(NODE_TYPE_SERVER)) + _server = (ManagedServer)parent.getManagedObject(); + + _virtualHostName = _selectedNode.getVirtualHost(); + } + + JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(_server); + if(serverRegistry != null){ + _mbsc = serverRegistry.getServerConnection(); + } + } + + public static ManagedServer getServer() + { + return _server; + } + + public static String getVirtualHost() + { + return _virtualHostName; + } + + private void showMBean(ManagedBean mbean) throws Exception + { + try + { + MBeanUtility.getMBeanInfo(mbean); + } + catch(Exception ex) + { + MBeanUtility.handleException(mbean, ex); + return; + } + + if (_tabFolder != null && !_tabFolder.isDisposed()) + { + _tabFolder.dispose(); + } + + _tabFolder = MBeanTabFolderFactory.generateMBeanTabFolder(_form.getBody(),(JMXManagedObject)mbean,_mbsc); + + int tabIndex = 0; + if (NOTIFICATIONS.equals(_selectedNode.getType())) + { + tabIndex = _tabFolder.getItemCount() -1; + } + + TabItem tab = _tabFolder.getItem(tabIndex); + // If folder is being set as visible after tab refresh, then the tab + // doesn't have the focus. + _tabFolder.setSelection(tabIndex); + refreshTab(tab); + } + + public void createPartControl(Composite parent) + { + // Create the Form + _toolkit = new FormToolkit(parent.getDisplay()); + _form = _toolkit.createForm(parent); + _form.getBody().setLayout(new FormLayout()); + _form.setText(APPLICATION_NAME); + + // Add selection listener for selection events in the Navigation view + getSite().getPage().addSelectionListener(NavigationView.ID, _selectionListener); + + createNotificationsTabFolder(); + + ViewUtility.setMBeanView(this); + + _backAction = new BackAction(); + getViewSite().getActionBars().getToolBarManager().add(_backAction); + _backAction.setEnabled(false); + _backHistory = new LinkedList<Object>(); + } + + private void refreshTab(TabItem tab) + { + if (tab == null) + { + return; + } + + TabControl controller = (TabControl)tab.getData(TabControl.CONTROLLER); + if(controller != null) + { + controller.refresh(_mbean); + } + } + + public void setFocus() + { + //_form.setFocus(); + } + + public void dispose() + { + _toolkit.dispose(); + super.dispose(); + } + + + private void createNotificationsTabFolder() + { + _notificationTabFolder = new TabFolder(_form.getBody(), SWT.NONE); + FormData layoutData = new FormData(); + layoutData.left = new FormAttachment(0); + layoutData.top = new FormAttachment(0); + layoutData.right = new FormAttachment(100); + layoutData.bottom = new FormAttachment(100); + _notificationTabFolder.setLayoutData(layoutData); + _notificationTabFolder.setVisible(false); + + VHNotificationsTabControl controller = new VHNotificationsTabControl(_notificationTabFolder); + TabItem tab = new TabItem(_notificationTabFolder, SWT.NONE); + tab.setText(NOTIFICATIONS); + tab.setData(TabControl.CONTROLLER, controller); + tab.setControl(controller.getControl()); + } + + private void refreshNotificationPage() + { + TabItem tab = _notificationTabFolder.getItem(0); + VHNotificationsTabControl controller = (VHNotificationsTabControl)tab.getData(TabControl.CONTROLLER); + controller.refresh(); + _notificationTabFolder.setVisible(true); + } + + + + private void generateTypeTabFolder() throws Exception + { + if (_typeTabFolder != null && !_typeTabFolder.isDisposed()) + { + _typeTabFolder.dispose(); + } + + //Generates the full Queue/Connection/Exchange selection tab set + _typeTabFolder = MBeanTabFolderFactory.generateMBeanTypeTabFolder( + _form.getBody(), getServer(), getVirtualHost()); + refreshTab(_typeTabFolder.getItem(0)); + } + + private void showTypeTabFolder(String type) throws Exception + { + if (_typeTabFolder != null && !_typeTabFolder.isDisposed()) + { + _typeTabFolder.dispose(); + } + + if (CONNECTION.equals(type)) + { + //Generates the Connection selection tab + _typeTabFolder = MBeanTabFolderFactory.generateConnectionTypeTabFolder( + _form.getBody(), getServer(), getVirtualHost()); + refreshTab(_typeTabFolder.getItem(0)); + } + else if (EXCHANGE.equals(type)) + { + //Generates the Exchange selection tab + _typeTabFolder = MBeanTabFolderFactory.generateExchangeTypeTabFolder( + _form.getBody(), getServer(), getVirtualHost()); + refreshTab(_typeTabFolder.getItem(0)); + } + else if (QUEUE.equals(type)) + { + //Generates the Queue selection tab + _typeTabFolder = MBeanTabFolderFactory.generateQueueTypeTabFolder( + _form.getBody(), getServer(), getVirtualHost()); + refreshTab(_typeTabFolder.getItem(0)); + } + } + + private void clearView() + { + if (_tabFolder != null && !_tabFolder.isDisposed()) + { + _tabFolder.setVisible(false); + } + + if (_typeTabFolder != null && !_typeTabFolder.isDisposed()) + { + _typeTabFolder.setVisible(false); + } + + if (_notificationTabFolder != null && !_notificationTabFolder.isDisposed()) + { + _notificationTabFolder.setVisible(false); + } + + _form.setText(APPLICATION_NAME); + clearStatusBar(); + } + + public void mbeanUnregistered(ManagedBean mbean) + { + //if the mbean is actually open, clear the view and empty the Back history + if(mbean == _mbean) + { + clearView(); + _backHistory.clear(); + _backAction.setEnabled(false); + ViewUtility.popupInfoMessage("MBean Unregistered", + "The open MBean was unregistered from the server."); + } + } + + public void refresh() + { + if(!ApplicationRegistry.isServerConnected(_server)) + { + return; + } + + if (_tabFolder != null && !_tabFolder.isDisposed()) + { + if(_tabFolder.getVisible()) + { + int selectedTab = _tabFolder.getSelectionIndex(); + TabItem tab = _tabFolder.getItem(selectedTab); + TabControl controller = (TabControl) tab.getData(TabControl.CONTROLLER); + if(controller != null) + { + controller.refresh(_mbean); + } + return; + } + } + + if (_typeTabFolder != null && !_typeTabFolder.isDisposed()) + { + + if(_typeTabFolder.getVisible()) + { + int selectedTab = _typeTabFolder.getSelectionIndex(); + TabItem tab = _typeTabFolder.getItem(selectedTab); + TabControl controller = (TabControl) tab.getData(TabControl.CONTROLLER); + if(controller != null) + { + controller.refresh(_mbean); + } + return; + } + } + + if (_notificationTabFolder != null && !_notificationTabFolder.isDisposed()) + { + if(_notificationTabFolder.getVisible()) + { + int selectedTab = _notificationTabFolder.getSelectionIndex(); + TabItem tab = _notificationTabFolder.getItem(selectedTab); + TabControl controller = (TabControl) tab.getData(TabControl.CONTROLLER); + if(controller != null) + { + controller.refresh(_mbean); + } + return; + } + } + } + + public void populateStatusBar(Image icon, String message) + { + IActionBars bars = getViewSite().getActionBars(); + bars.getStatusLineManager().setMessage(icon, message); + } + + public void populateStatusBar(String message) + { + IActionBars bars = getViewSite().getActionBars(); + bars.getStatusLineManager().setMessage(message); + } + + public void clearStatusBar() + { + populateStatusBar(""); + } + + public void back() throws Exception + { + if(_backHistory.isEmpty()) + { + return; + } + + Object previous = _backHistory.removeLast(); + if(_backHistory.isEmpty()) + { + //if this is the last history item, disable the action button + _backAction.setEnabled(false); + } + + if(previous instanceof ManagedBean) + { + openMBean((ManagedBean)previous, true); + } + else if (previous instanceof TreeObject) + { + _mbean = null; + clearView(); + setFormTitle(); + + TreeObject node = (TreeObject) previous; + String mbeanType = node.getType(); + + if (NODE_TYPE_TYPEINSTANCE.equals(mbeanType)) + { + generateTypeTabFolder(); + } + else if (NODE_TYPE_MBEANTYPE.equals(mbeanType)) + { + showTypeTabFolder(node.getName()); + } + } + + _form.layout(true); + _form.getBody().layout(true, true); + } +} 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(); + } + }); + } + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java new file mode 100644 index 0000000000..ea49a5c006 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java @@ -0,0 +1,388 @@ +/* + * + * 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.BUTTON_CLEAR; +import static org.apache.qpid.management.ui.Constants.DESCRIPTION; +import static org.apache.qpid.management.ui.Constants.FONT_BOLD; +import static org.apache.qpid.management.ui.Constants.FONT_BUTTON; +import static org.apache.qpid.management.ui.Constants.FONT_ITALIC; +import static org.apache.qpid.management.ui.Constants.SUBSCRIBE_BUTTON; +import static org.apache.qpid.management.ui.Constants.UNSUBSCRIBE_BUTTON; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.ServerRegistry; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.model.NotificationInfoModel; +import org.apache.qpid.management.ui.model.NotificationObject; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.TabFolder; + +/** + * Creates control composite for Notifications tab + * @author Bhupendra Bhardwaj + */ +public class NotificationsTabControl extends VHNotificationsTabControl +{ + private static final String SELECT_NOTIFICATIONNAME = "Select Notification"; + private static final String SELECT_NOTIFICATIONTYPE = "Select Type"; + private SelectionListener selectionListener; + private SelectionListener comboListener; + + private Combo _notificationNameCombo; + private Combo _typesCombo; + private Label _descriptionLabel; + private Button _subscribeButton; + private Button _unsubscribeButton; + + public NotificationsTabControl(TabFolder tabFolder, ManagedBean mbean) + { + super(tabFolder); + _mbean = mbean; + + populateNotificationInfo(); + } + + protected void createWidgets() + { + selectionListener = new SelectionListenerImpl(); + comboListener = new ComboSelectionListener(); + createNotificationInfoComposite(); + addButtons(); + createTableViewer(); + } + + /** + * Creates composite and populates for displaying Notification Information (name, type, description) + * and creates buttons for subscribing or unsubscribing for notifications + */ + private void createNotificationInfoComposite() + { + Composite composite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + composite.setLayout(new FormLayout()); + + Label label = _toolkit.createLabel(composite, "Select the notification to subscribe or unsubscribe"); + label.setFont(ApplicationRegistry.getFont(FONT_BOLD)); + FormData formData = new FormData(); + formData.top = new FormAttachment(0, 10); + formData.left = new FormAttachment(0, 10); + label.setLayoutData(formData); + + _notificationNameCombo = new Combo(composite, SWT.READ_ONLY | SWT.DROP_DOWN); + formData = new FormData(); + formData.top = new FormAttachment(label, 10); + formData.left = new FormAttachment(0, 10); + formData.right = new FormAttachment(40); + _notificationNameCombo.setLayoutData(formData); + _notificationNameCombo.addSelectionListener(comboListener); + + _typesCombo = new Combo(composite, SWT.READ_ONLY | SWT.DROP_DOWN); + formData = new FormData(); + formData.top = new FormAttachment(label, 10); + formData.left = new FormAttachment(_notificationNameCombo, 5); + formData.right = new FormAttachment(65); + _typesCombo.setLayoutData(formData); + _typesCombo.addSelectionListener(comboListener); + + _subscribeButton = new Button(composite, SWT.PUSH | SWT.CENTER); + _subscribeButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + _subscribeButton.setText(SUBSCRIBE_BUTTON); + formData = new FormData(); + formData.top = new FormAttachment(label, 10); + formData.left = new FormAttachment(65, 10); + formData.width = 80; + _subscribeButton.setLayoutData(formData); + _subscribeButton.addSelectionListener(selectionListener); + + _unsubscribeButton = new Button(composite, SWT.PUSH | SWT.CENTER); + _unsubscribeButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + _unsubscribeButton.setText(UNSUBSCRIBE_BUTTON); + formData = new FormData(); + formData.top = new FormAttachment(label, 10); + formData.left = new FormAttachment(_subscribeButton, 10); + formData.width = 80; + _unsubscribeButton.setLayoutData(formData); + _unsubscribeButton.addSelectionListener(selectionListener); + + Label fixedLabel = _toolkit.createLabel(composite, ""); + formData = new FormData(); + formData.top = new FormAttachment(_notificationNameCombo, 5); + formData.left = new FormAttachment(0, 10); + fixedLabel.setLayoutData(formData); + fixedLabel.setText(DESCRIPTION + " : "); + fixedLabel.setFont(ApplicationRegistry.getFont(FONT_BOLD)); + + _descriptionLabel = _toolkit.createLabel(composite, ""); + formData = new FormData(); + formData.top = new FormAttachment(_notificationNameCombo, 5); + formData.left = new FormAttachment(fixedLabel, 10); + formData.right = new FormAttachment(100); + _descriptionLabel.setLayoutData(formData); + _descriptionLabel.setText(" "); + _descriptionLabel.setFont(ApplicationRegistry.getFont(FONT_ITALIC)); + } + + /** + * Creates clear button + */ + protected void addButtons() + { + Composite composite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + composite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); + composite.setLayout(new GridLayout(2,false)); + + // Add Clear Button + _clearButton = _toolkit.createButton(composite, BUTTON_CLEAR, SWT.PUSH | SWT.CENTER); + _clearButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + GridData gridData = new GridData(SWT.LEAD, SWT.TOP, true, false); + gridData.widthHint = 80; + _clearButton.setLayoutData(gridData); + _clearButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + if (_mbean == null) + { + return; + } + + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer()); + IStructuredSelection ss = (IStructuredSelection)_tableViewer.getSelection(); + if(!ss.isEmpty()) + { + //clear selected Notifications + serverRegistry.clearNotifications(_mbean, ss.toList()); + } + else if(_notifications != null) + { + //clear all the notifications, if there are any + + //check the user is certain of this clear-all operation + int response = ViewUtility.popupOkCancelConfirmationMessage( + "Clear Notifications", "Clear all Notifications for this MBean?"); + if(response != SWT.OK) + { + return; + } + + synchronized(this) + { + List<NotificationObject> newList = new ArrayList<NotificationObject>(); + newList.addAll(_notifications); + serverRegistry.clearNotifications(_mbean, newList); + } + } + + refresh(); + } + }); + //add description + Label desc = _toolkit.createLabel(composite,"Clears the selected Notifications, or all if none are selected"); + desc.setLayoutData(new GridData(SWT.LEFT,SWT.CENTER, false, false)); + } + + @Override + public void refresh(ManagedBean mbean) + { + refresh(); + } + + /** + * Fills the notification information widgets for selected mbean + */ + private void populateNotificationInfo() + { + _notificationNameCombo.removeAll(); + NotificationInfoModel[] items = MBeanUtility.getNotificationInfo(_mbean); + if (items.length > 1) + { + _notificationNameCombo.add(SELECT_NOTIFICATIONNAME); + } + + for (int i = 0; i < items.length; i++) + { + _notificationNameCombo.add(items[i].getName()); + _notificationNameCombo.setData(items[i].getName(), items[i]); + } + _notificationNameCombo.select(0); + + _typesCombo.removeAll(); + _typesCombo.add("Select Type", 0); + _typesCombo.select(0); + _typesCombo.setEnabled(false); + + populateNotificationType(_notificationNameCombo.getItem(0)); + checkForEnablingButtons(); + } + + /** + * Checks and the enabing/disabling of buttons + */ + private void checkForEnablingButtons() + { + int nameIndex = _notificationNameCombo.getSelectionIndex(); + int itemCount = _notificationNameCombo.getItems().length; + if ((itemCount > 1) && (nameIndex == 0)) + { + _subscribeButton.setEnabled(false); + _unsubscribeButton.setEnabled(false); + _descriptionLabel.setText(""); + return; + } + + int typeIndex = _typesCombo.getSelectionIndex(); + itemCount = _typesCombo.getItems().length; + if ((itemCount > 1) && (typeIndex == 0)) + { + _subscribeButton.setEnabled(false); + _unsubscribeButton.setEnabled(false); + return; + } + + String type = _typesCombo.getItem(typeIndex); + String name = _notificationNameCombo.getItem(nameIndex); + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean); + + if (serverRegistry.hasSubscribedForNotifications(_mbean, name, type)) + { + _subscribeButton.setEnabled(false); + _unsubscribeButton.setEnabled(true); + } + else + { + _subscribeButton.setEnabled(true); + _unsubscribeButton.setEnabled(false); + } + } + + /** + * Selection listener for subscribing or unsubscribing the notifications + */ + private class SelectionListenerImpl extends SelectionAdapter + { + public void widgetSelected(SelectionEvent e) + { + if (_mbean == null) + return; + + Button source = (Button)e.getSource(); + String type = _typesCombo.getItem(_typesCombo.getSelectionIndex()); + String name = _notificationNameCombo.getItem(_notificationNameCombo.getSelectionIndex()); + if (source == _unsubscribeButton) + { + try + { + MBeanUtility.removeNotificationListener(_mbean, name, type); + } + catch(Exception ex) + { + MBeanUtility.handleException(ex); + } + } + else if (source == _subscribeButton) + { + try + { + MBeanUtility.createNotificationlistener(_mbean, name, type); + } + catch(Exception ex) + { + MBeanUtility.handleException(ex); + } + } + checkForEnablingButtons(); + } + } + + /** + * Selection listener class for the Notification Name. The notification type and description will be + * displayed accordingly + */ + private class ComboSelectionListener extends SelectionAdapter + { + public void widgetSelected(SelectionEvent e) + { + if (_mbean == null) + return; + + Combo combo = (Combo)e.getSource(); + if (combo == _notificationNameCombo) + { + String selectedItem = combo.getItem(combo.getSelectionIndex()); + populateNotificationType(selectedItem); + } + checkForEnablingButtons(); + } + } + + private void populateNotificationType(String notificationName) + { + NotificationInfoModel data = (NotificationInfoModel)_notificationNameCombo.getData(notificationName); + if (data == null) + { + _descriptionLabel.setText(""); + _typesCombo.select(0); + _typesCombo.setEnabled(false); + return; + } + _descriptionLabel.setText(data.getDescription()); + _typesCombo.removeAll(); + _typesCombo.setItems(data.getTypes()); + if (_typesCombo.getItemCount() > 1) + { + _typesCombo.add(SELECT_NOTIFICATIONTYPE, 0); + } + _typesCombo.select(0); + _typesCombo.setEnabled(true); + } + + /** + * Updates the table with new notifications received from mbean server for the selected mbean + */ + protected void updateTableViewer() + { + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean); + List<NotificationObject> newList = serverRegistry.getNotifications(_mbean); + synchronized(this) + { + _notifications = newList; + _tableViewer.setInput(_notifications); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NumberVerifyListener.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NumberVerifyListener.java new file mode 100644 index 0000000000..1774209dae --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NumberVerifyListener.java @@ -0,0 +1,46 @@ +/* + * + * 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 org.eclipse.swt.events.VerifyEvent; +import org.eclipse.swt.events.VerifyListener; + +/** + * Implementation of VeryfyListener for numeric values + * @author Bhupendra Bhardwaj + */ +public class NumberVerifyListener implements VerifyListener +{ + public void verifyText(VerifyEvent event) + { + String string = event.text; + char [] chars = new char [string.length ()]; + string.getChars (0, chars.length, chars, 0); + for (int i=0; i<chars.length; i++) + { + if (!('0' <= chars [i] && chars [i] <= '9')) + { + event.doit = false; + return; + } + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java new file mode 100644 index 0000000000..d0b70f4340 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java @@ -0,0 +1,920 @@ +/* + * + * 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 java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; + +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularDataSupport; + +import static org.apache.qpid.management.ui.Constants.*; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.model.OperationData; +import org.apache.qpid.management.ui.model.ParameterData; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.events.VerifyEvent; +import org.eclipse.swt.events.VerifyListener; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.Form; +import org.eclipse.ui.forms.widgets.FormToolkit; + + +/** + * Control class for the MBean operations tab. It creates the required widgets + * for the selected MBean. + */ +public class OperationTabControl extends TabControl +{ + private static final int heightForAParameter = 30; + private static final int labelWidth = 30; + private static final int valueWidth = labelWidth + 25; + + private FormToolkit _toolkit; + private Form _form; + private OperationData _opData; + + private SelectionListener operationExecutionListener = new OperationExecutionListener(); + private SelectionListener refreshListener = new RefreshListener(); + private SelectionListener parameterSelectionListener = new ParameterSelectionListener(); + private SelectionListener booleanSelectionListener = new BooleanSelectionListener(); + private VerifyListener verifyListener = new VerifyListenerImpl(); + private KeyListener keyListener = new KeyListenerImpl(); + private KeyListener headerBindingListener = new HeaderBindingKeyListener(); + + private Composite _headerComposite = null; + private Composite _paramsComposite = null; + private Composite _resultsComposite = null; + private Button _executionButton = null; + + // for customized method in header exchange + private HashMap<Text, Text> headerBindingHashMap = null; + private String _virtualHostName = null; + + public OperationTabControl(TabFolder tabFolder, OperationData opData) + { + super(tabFolder); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + _opData = opData; + createComposites(); + setHeader(); + } + + /** + * Form area is devided in four parts: + * Header composite - displays operaiton information + * Patameters composite - displays parameters if there + * Button - operation execution button + * Results composite - displays results for operations, which have + * no parameters but have some return value + */ + private void createComposites() + { + // + _headerComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _headerComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + List<ParameterData> params = _opData.getParameters(); + if (params != null && !params.isEmpty()) + { + _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + } + _executionButton = _toolkit.createButton(_form.getBody(), BUTTON_EXECUTE, SWT.PUSH | SWT.CENTER); + _executionButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + GridData layoutData = new GridData(SWT.CENTER, SWT.TOP, true, false); + layoutData.verticalIndent = 20; + _executionButton.setLayoutData(layoutData); + + _resultsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + layoutData.verticalIndent = 20; + _resultsComposite.setLayoutData(layoutData); + _resultsComposite.setLayout(new GridLayout()); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + @Override + public void refresh(ManagedBean mbean) + { + _mbean = mbean; + _virtualHostName = _mbean.getVirtualHostName(); + + // Setting the form to be invisible. Just in case the mbean server connection + // is done and it takes time in getting the response, then the ui should be blank + // instead of having half the widgets displayed. + _form.setVisible(false); + + ViewUtility.disposeChildren(_paramsComposite); + createParameterWidgets(); + + // Set button text and add appropriate listener to button. + // If there are no parameters and it is info operation, then operation gets executed + // and result is displayed + List<ParameterData> params = _opData.getParameters(); + if (params != null && !params.isEmpty()) + { + setButton(BUTTON_EXECUTE); + } + else if (_opData.getImpact() == OPERATION_IMPACT_ACTION) + { + setButton(BUTTON_EXECUTE); + } + else if (_opData.getImpact() == OPERATION_IMPACT_INFO) + { + setButton(BUTTON_REFRESH); + executeAndShowResults(); + } + + _form.setVisible(true); + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + /** + * populates the header composite, containing the operation name and description. + */ + private void setHeader() + { + _form.setText(ViewUtility.getDisplayText(_opData.getName())); + _headerComposite.setLayout(new GridLayout(2, false)); + //operation description + Label label = _toolkit.createLabel(_headerComposite, DESCRIPTION + " : "); + label.setFont(ApplicationRegistry.getFont(FONT_BOLD)); + label.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false)); + + label = _toolkit.createLabel(_headerComposite, _opData.getDescription()); + label.setFont(ApplicationRegistry.getFont(FONT_NORMAL)); + label.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, true, false)); + + _headerComposite.layout(); + } + + /** + * Creates the widgets for operation parameters if there are any + */ + private void createParameterWidgets() + { + List<ParameterData> params = _opData.getParameters(); + if (params == null || params.isEmpty()) + { + return; + } + + // Customised parameter widgets + if (_mbean.isExchange() && + HEADERS_EXCHANGE.equals(_mbean.getProperty(EXCHANGE_TYPE)) && + _opData.getName().equalsIgnoreCase(OPERATION_CREATE_BINDING)) + { + customCreateNewBinding(); + return; + } + // end of Customised parameter widgets + + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + _paramsComposite.setLayout(new FormLayout()); + int parameterPositionOffset = 0; + for (ParameterData param : params) + { + boolean valueInCombo = false; + Label label = _toolkit.createLabel(_paramsComposite, ViewUtility.getDisplayText(param.getName())); + FormData formData = new FormData(); + if (params.indexOf(param) == 0) + { + parameterPositionOffset = 0; + } + else + { + parameterPositionOffset += heightForAParameter; + } + formData.top = new FormAttachment(0, parameterPositionOffset + 2); + formData.right = new FormAttachment(labelWidth); + label.setLayoutData(formData); + label.setToolTipText(param.getDescription()); + + formData = new FormData(); + formData.top = new FormAttachment(0, parameterPositionOffset); + formData.left = new FormAttachment(label, 5); + formData.right = new FormAttachment(valueWidth); + // this will contain the list of items, if the list is to be made available to choose from + // e.g. the list of exchanges + String[] items = null; + if (param.getName().equals(QUEUE)) + { + List<String> qList = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_virtualHostName); + // Customization for AMQQueueMBean method OPERATION_MOVE_MESSAGES + if (_opData.getName().equals(OPERATION_MOVE_MESSAGES)) + { + qList.remove(_mbean.getName()); + } + // End of Customization + items = qList.toArray(new String[0]); + } + else if (param.getName().equals(EXCHANGE)) + { + items = ApplicationRegistry.getServerRegistry(_mbean).getExchangeNames(_virtualHostName); + } + else if (param.getName().equals(EXCHANGE_TYPE)) + { + items = DEFAULT_EXCHANGE_TYPE_VALUES.toArray(new String[DEFAULT_EXCHANGE_TYPE_VALUES.size()]); + } + else if (isUserListParameter(param)) + { + List<String> list = ApplicationRegistry.getServerRegistry(_mbean).getUsernames(); + if (list != null && !list.isEmpty()) + { + items = list.toArray(new String[0]); + } + } + + if (items != null) + { + org.eclipse.swt.widgets.List _list = new org.eclipse.swt.widgets.List(_paramsComposite, SWT.BORDER | SWT.V_SCROLL); + int listSize = _form.getClientArea().height * 2 / 3; + int itemsHeight = items.length * (_list.getItemHeight() + 2); + // Set a min height for the list widget (set it to min 4 items) + if (items.length < 4) + { + itemsHeight = 4 * (_list.getItemHeight() + 2); + } + + listSize = (listSize > itemsHeight) ? itemsHeight : listSize; + parameterPositionOffset = parameterPositionOffset + listSize; + formData.bottom = new FormAttachment(0, parameterPositionOffset); + _list.setLayoutData(formData); + _list.setData(param); + _list.setItems(items); + _list.addSelectionListener(parameterSelectionListener); + valueInCombo = true; + } + else if (param.isBoolean()) + { + Button booleanButton = _toolkit.createButton(_paramsComposite, "", SWT.CHECK); + booleanButton.setLayoutData(formData); + booleanButton.setData(param); + booleanButton.addSelectionListener(booleanSelectionListener); + valueInCombo = true; + } + else + { + int style = SWT.NONE; + if (PASSWORD.equalsIgnoreCase(param.getName())) + { + style = SWT.PASSWORD; + } + Text text = _toolkit.createText(_paramsComposite, "", style); + formData = new FormData(); + formData.top = new FormAttachment(0, parameterPositionOffset); + formData.left = new FormAttachment(label, 5); + formData.right = new FormAttachment(valueWidth); + text.setLayoutData(formData); + // Listener to assign value to the parameter + text.addKeyListener(keyListener); + // Listener to verify if the entered key is valid + text.addVerifyListener(verifyListener); + text.setData(param); + } + + // display the parameter data type next to the text field + if (valueInCombo) + { + label = _toolkit.createLabel(_paramsComposite, ""); + } + else if (PASSWORD.equalsIgnoreCase(param.getName())) + { + label = _toolkit.createLabel(_paramsComposite, "(String)"); + } + else + { + String str = param.getType(); + + if (param.getType().lastIndexOf(".") != -1) + str = param.getType().substring(1 + param.getType().lastIndexOf(".")); + + label = _toolkit.createLabel(_paramsComposite, "(" + str + ")"); + } + formData = new FormData(); + formData.top = new FormAttachment(0, parameterPositionOffset); + formData.left = new FormAttachment(valueWidth, 5); + label.setLayoutData(formData); + } + } + + private boolean isUserListParameter(ParameterData param) + { + if (_mbean.isAdmin() && param.getName().equals(OPERATION_PARAM_USERNAME) + && !_opData.getName().equals(OPERATION_CREATEUSER)) + { + return true; + } + + return false; + } + + /** + * Creates customized dispaly for a method "CreateNewBinding" for Headers exchange + * + */ + private void customCreateNewBinding() + { + headerBindingHashMap = new HashMap<Text, Text>(); + + _paramsComposite.setLayout(new GridLayout()); + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true)); + final ScrolledComposite scrolledComposite = new ScrolledComposite(_paramsComposite, SWT.BORDER | SWT.V_SCROLL); + scrolledComposite.setExpandHorizontal(true); + scrolledComposite.setExpandVertical(true); + GridData layoutData = new GridData(SWT.FILL, SWT.TOP, true, true); + scrolledComposite.setLayoutData(layoutData); + scrolledComposite.setLayout(new GridLayout()); + + final Composite composite = _toolkit.createComposite(scrolledComposite, SWT.NONE); + scrolledComposite.setContent(composite); + layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + layoutData.verticalIndent = 20; + composite.setLayoutData(layoutData); + composite.setLayout(new FormLayout()); + + List<ParameterData> params = _opData.getParameters(); + ParameterData param = params.get(0); + // Queue selection widget + Label label = _toolkit.createLabel(composite, ViewUtility.getDisplayText(param.getName())); + FormData formData = new FormData(); + formData.top = new FormAttachment(0, 2); + formData.right = new FormAttachment(labelWidth); + label.setLayoutData(formData); + label.setToolTipText(param.getDescription()); + + formData = new FormData(); + formData.top = new FormAttachment(0); + formData.left = new FormAttachment(label, 5); + formData.right = new FormAttachment(valueWidth); + + Combo combo = new Combo(composite, SWT.READ_ONLY | SWT.DROP_DOWN); + List<String> qList = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_virtualHostName); + combo.setItems(qList.toArray(new String[0])); + combo.add("Select Queue", 0); + combo.select(0); + combo.setLayoutData(formData); + combo.setData(param); + combo.addSelectionListener(parameterSelectionListener); + + // Binding creation widgets + createARowForCreatingHeadersBinding(composite, 1); + createARowForCreatingHeadersBinding(composite, 2); + createARowForCreatingHeadersBinding(composite, 3); + createARowForCreatingHeadersBinding(composite, 4); + createARowForCreatingHeadersBinding(composite, 5); + createARowForCreatingHeadersBinding(composite, 6); + createARowForCreatingHeadersBinding(composite, 7); + createARowForCreatingHeadersBinding(composite, 8); + + final Button addMoreButton = _toolkit.createButton(composite, "Add More", SWT.PUSH); + formData = new FormData(); + formData.top = new FormAttachment(0, heightForAParameter); + formData.left = new FormAttachment(70, 5); + addMoreButton.setLayoutData(formData); + addMoreButton.setData("rowCount", 8); + addMoreButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int count = Integer.parseInt(addMoreButton.getData("rowCount").toString()); + createARowForCreatingHeadersBinding(composite, ++count); + addMoreButton.setData("rowCount", count); + scrolledComposite.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + composite.layout(); + _form.layout(); + } + }); + + scrolledComposite.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + composite.layout(); + } + + /** + * Adds a row for adding a binding for Headers Exchange. Used by the method, which creates the customized + * layout and widgest for Header's exchange method createNewBinding. + * @param parent composite + * @param rowCount - row number + */ + private void createARowForCreatingHeadersBinding(Composite parent, int rowCount) + { + Label key = _toolkit.createLabel(parent, "Name"); + FormData formData = new FormData(); + formData.top = new FormAttachment(0, rowCount * heightForAParameter + 2); + formData.right = new FormAttachment(15); + key.setLayoutData(formData); + + Text keyText = _toolkit.createText(parent, "", SWT.NONE); + formData = new FormData(); + formData.top = new FormAttachment(0, rowCount * heightForAParameter); + formData.left = new FormAttachment(key, 5); + formData.right = new FormAttachment(40); + keyText.setLayoutData(formData); + keyText.addKeyListener(headerBindingListener); + + Label value = _toolkit.createLabel(parent, "Value"); + formData = new FormData(); + formData.top = new FormAttachment(0, rowCount * heightForAParameter + 2); + formData.right = new FormAttachment(45); + value.setLayoutData(formData); + + Text valueText = _toolkit.createText(parent, "", SWT.NONE); + formData = new FormData(); + formData.top = new FormAttachment(0, rowCount * heightForAParameter); + formData.left = new FormAttachment(value, 5); + formData.right = new FormAttachment(70); + valueText.setLayoutData(formData); + valueText.addKeyListener(headerBindingListener); + + // Add these to the map, to retrieve the values while setting the parameter value + headerBindingHashMap.put(keyText, valueText); + } + + /** + * Sets text and listener for the operation execution button + * @param text + */ + private void setButton(String text) + { + _executionButton.setText(text); + _executionButton.removeSelectionListener(refreshListener); + _executionButton.removeSelectionListener(operationExecutionListener); + + if (BUTTON_EXECUTE.equals(text)) + { + _executionButton.addSelectionListener(operationExecutionListener); + } + else + { + _executionButton.addSelectionListener(refreshListener); + } + } + + /** + * displays the operation result in a pop-up window + * @param result + */ + private void populateResults(Object result) + { + Display display = Display.getCurrent(); + int width = 610; + int height = 400; + Shell shell = ViewUtility.createPopupShell(RESULT, width, height); + shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE)); + ViewUtility.populateCompositeWithData(_toolkit, shell, result); + + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + shell.dispose(); + } + + /** + * Clears the parameter values of the operation + */ + private void clearParameters() + { + List<ParameterData> params = _opData.getParameters(); + if (params != null && !params.isEmpty()) + { + for (ParameterData param : params) + { + param.setDefaultValue(); + } + } + } + + /** + * Clears the values entered by the user from parameter value widgets + * @param control + */ + private void clearParameterValues(Composite control) + { + if (control == null || (control.isDisposed())) + return; + + Control[] controls = control.getChildren(); + if (controls == null || controls.length == 0) + return; + + for (int i = 0; i < controls.length; i++) + { + if (controls[i] instanceof Combo) + ((Combo)controls[i]).select(0); + if (controls[i] instanceof org.eclipse.swt.widgets.List) + ((org.eclipse.swt.widgets.List)controls[i]).deselectAll(); + else if (controls[i] instanceof Text) + ((Text)controls[i]).setText(""); + else if (controls[i] instanceof Button) + ((Button)controls[i]).setSelection(false); + else if (controls[i] instanceof Composite) + clearParameterValues((Composite)controls[i]); + } + } + + /** + * Listener class for operation execution events + */ + private class OperationExecutionListener extends SelectionAdapter + { + public void widgetSelected(SelectionEvent e) + { + List<ParameterData> params = _opData.getParameters(); + if (params != null && !params.isEmpty()) + { + for (ParameterData param : params) + { + if (param.getValue() == null || param.getValue().toString().length() == 0) + { + // Customized check, because for this parameter null is allowed + if (param.getName().equals(ATTRIBUTE_QUEUE_OWNER) && + _opData.getName().equals(OPERATION_CREATE_QUEUE)) + { + continue; + } + // End of custom code + + ViewUtility.popupInfoMessage(_form.getText(), "Please select the " + ViewUtility.getDisplayText(param.getName())); + return; + } + + //Custom handling for the PASSWORD field + if (param.getName().equalsIgnoreCase(PASSWORD)) + { + //Convert the String value to a character array if that is what is required. + if (param.getType().equals("[C")) + { + // Retreive the mBean type and version. + // If we have a version 1 UserManagement class mbean then it expects the password + // to be sent as the hashed version. + if (_mbean.getType().equals("UserManagement") && _mbean.getVersion() == 1) + { + try + { + param.setValue(ViewUtility.getHash((String) param.getValue())); + } + catch (Exception hashException) + { + ViewUtility.popupErrorMessage(_form.getText(), + "Unable to calculate hash for Password:" + + hashException.getMessage()); + return; + } + } + else + { + param.setValue(((String) param.getValue()).toCharArray()); + } + } + } + // end of customization + + } + } + + if (_opData.getImpact() == OPERATION_IMPACT_ACTION) + { + String bean = _mbean.getName() == null ? _mbean.getType() : _mbean.getName(); + int response = ViewUtility.popupConfirmationMessage(bean, "Do you want to " + _form.getText()+ " ?"); + if (response == SWT.YES) + { + executeAndShowResults(); + } + } + else + { + executeAndShowResults(); + } + + if (_mbean.isAdmin() && _opData.getName().equals(OPERATION_DELETEUSER)) + { + refresh(_mbean); + } + else + { + clearParameters(); + clearParameterValues(_paramsComposite); + } + } + } + + // Listener for the "Refresh" execution button + private class RefreshListener extends SelectionAdapter + { + public void widgetSelected(SelectionEvent e) + { + executeAndShowResults(); + } + } + + /** + * Executres the operation, gets the result from server and displays to the user + */ + private void executeAndShowResults() + { + Object result = null; + try + { + result = MBeanUtility.execute(_mbean, _opData); + } + catch(Exception ex) + { + MBeanUtility.handleException(_mbean, ex); + return; + } + + // Custom code for Admin mbean operation + /* These custome codes here are to make the GUI look more user friendly. + * Here we are adding the users to a list, which will be used to list username to be selected on + * pages like "delete user", "set password" instead of typing the username + */ + if (_mbean.isAdmin()) + { + if (_opData.getName().equals(OPERATION_VIEWUSERS)) + { + ApplicationRegistry.getServerRegistry(_mbean).setUserList(extractUserList(result)); + } + else if (_opData.getName().equals(OPERATION_DELETEUSER)) + { + List<String> list = ApplicationRegistry.getServerRegistry(_mbean).getUsernames(); + Object userName = _opData.getParameterValue(OPERATION_PARAM_USERNAME); + if ((list != null) && !list.isEmpty() && (userName != null)) + { + list.remove(userName); + ApplicationRegistry.getServerRegistry(_mbean).setUserList(list); + } + } + else if (_opData.getName().equals(OPERATION_CREATEUSER)) + { + List<String> list = ApplicationRegistry.getServerRegistry(_mbean).getUsernames(); + Object userName = _opData.getParameterValue(OPERATION_PARAM_USERNAME); + if ((list != null) && !list.isEmpty() && (userName != null)) + { + list.add(userName.toString()); + ApplicationRegistry.getServerRegistry(_mbean).setUserList(list); + } + } + } + // end of custom code + + // Some mbeans have only "type" and no "name". + String title = _mbean.getType(); + if (_mbean.getName() != null && _mbean.getName().length() != 0) + { + title = _mbean.getName(); + } + + if (_opData.isReturnTypeVoid()) + { + ViewUtility.popupInfoMessage(title, OPERATION_SUCCESSFUL); + } + else if (_opData.isReturnTypeBoolean()) + { + boolean success = Boolean.parseBoolean(result.toString()); + String message = success ? OPERATION_SUCCESSFUL : OPERATION_UNSUCCESSFUL; + if(success) + { + ViewUtility.popupInfoMessage(title, message); + } + else + { + ViewUtility.popupErrorMessage(title, message); + } + } + else if (_opData.getParameters() != null && !_opData.getParameters().isEmpty()) + { + populateResults(result); + } + else + { + ViewUtility.disposeChildren(_resultsComposite); + ViewUtility.populateCompositeWithData(_toolkit, _resultsComposite, result); + _resultsComposite.layout(); + _form.layout(); + } + + } + + private List<String> extractUserList(Object result) + { + if (!(result instanceof TabularDataSupport)) + { + return null; + } + + TabularDataSupport tabularData = (TabularDataSupport)result; + Collection<Object> records = tabularData.values(); + List<String> list = new ArrayList<String>(); + for (Object o : records) + { + CompositeData data = (CompositeData) o; + if (data.containsKey(USERNAME)) + { + list.add(data.get(USERNAME).toString()); + } + } + + return list; + } + + /** + * Listener class for the operation parameters widget + */ + private static class ParameterSelectionListener extends SelectionAdapter + { + public void widgetSelected(SelectionEvent e) + { + ParameterData parameter = (ParameterData)e.widget.getData(); + parameter.setValue(null); + if (e.widget instanceof Combo) + { + Combo combo = (Combo)e.widget; + if (combo.getSelectionIndex() > 0) + { + String item = combo.getItem(combo.getSelectionIndex()); + parameter.setValueFromString(item); + } + } + else if (e.widget instanceof org.eclipse.swt.widgets.List) + { + org.eclipse.swt.widgets.List list = (org.eclipse.swt.widgets.List)e.widget; + String[] selectedItems = list.getSelection(); + if (selectedItems.length > 0) + { + parameter.setValueFromString(selectedItems[0]); + } + } + } + } + + /** + * Listener class for boolean parameter widgets + */ + private static class BooleanSelectionListener extends SelectionAdapter + { + public void widgetSelected(SelectionEvent e) + { + ParameterData parameter = (ParameterData)(e.widget.getData()); + if (e.widget instanceof Button) + { + Button button = (Button)e.widget; + parameter.setValue(button.getSelection()); + } + else if (e.widget instanceof Combo) + { + Combo combo = (Combo)e.widget; + String item = combo.getItem(combo.getSelectionIndex()); + parameter.setValueFromString(item); + } + } + } + + /** + * Listener class for the operation parameter value widget (Text field) + */ + private static class KeyListenerImpl extends KeyAdapter + { + public void keyReleased(KeyEvent e) + { + if (!(e.widget instanceof Text)) + return; + + Text text = (Text)e.widget; + // Get the parameters widget and assign the text to the parameter + String strValue = text.getText(); + ParameterData parameter = (ParameterData)text.getData(); + try + { + parameter.setValueFromString(strValue); + } + catch(Exception ex) + { + // Exception occured in setting parameter value. + // ignore it. The value will not be assigned to the parameter + } + } + } + + /** + * Listener class for HeaderExchange's new binding widgets. Used when the new bindings are + * being created for Header's Exchange + */ + private class HeaderBindingKeyListener extends KeyAdapter + { + public void keyReleased(KeyEvent e) + { + ParameterData param = _opData.getParameters().get(1); + StringBuffer paramValue = new StringBuffer(); + for (Entry<Text, Text> entry : headerBindingHashMap.entrySet()) + { + + Text nameText = entry.getKey(); + String name = nameText.getText(); + Text valueText = entry.getValue(); + String value = valueText.getText(); + if ((name != null) && (name.length() != 0) && (value != null) && (value.length() != 0)) + { + if (paramValue.length() != 0) + { + paramValue.append(","); + } + paramValue.append(name + "=" + value); + } + } + + param.setValue(paramValue.toString()); + } + } + + /** + * Listener class for verifying the user input with parameter type + */ + private static class VerifyListenerImpl implements VerifyListener + { + public void verifyText(VerifyEvent event) + { + ParameterData parameter = (ParameterData)event.widget.getData(); + String text = event.text; + char [] chars = new char [text.length ()]; + text.getChars(0, chars.length, chars, 0); + String type = parameter.getType(); + if (type.equals("int") || type.equals("java.lang.Integer") || + type.equals("long") || type.equals("java.lang.Long")) + { + for (int i=0; i<chars.length; i++) + { + if (!('0' <= chars [i] && chars [i] <= '9')) + { + event.doit = false; + return; + } + } + + } + } + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java new file mode 100644 index 0000000000..156543d603 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java @@ -0,0 +1,103 @@ +/* + * + * 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 java.util.ArrayList; + +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.model.OperationData; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.TabFolder; + +/** + * Abstract class for all the control classes of tabs. + * @author Bhupendra Bhardwaj + */ +public abstract class TabControl +{ + public static final String CONTROLLER = "controller"; + protected ManagedBean _mbean = null; + protected TabFolder _tabFolder = null; + + private static java.util.List<String> simpleTypes = new ArrayList<String>(); + + static + { + simpleTypes.add("java.math.BigDecimal"); + simpleTypes.add("java.math.BigInteger"); + simpleTypes.add("java.lang.Boolean"); + simpleTypes.add("java.lang.Byte"); + simpleTypes.add("java.lang.Character"); + simpleTypes.add("java.util.Date"); + simpleTypes.add("java.lang.Double"); + simpleTypes.add("java.lang.Float"); + simpleTypes.add("java.lang.Integer"); + simpleTypes.add("java.lang.Long"); + simpleTypes.add("javax.management.ObjectName"); + simpleTypes.add("java.lang.Short"); + simpleTypes.add("java.lang.String"); + simpleTypes.add("boolean"); + } + + public TabControl(TabFolder tabFolder) + { + _tabFolder = tabFolder; + } + + /** + * @return controller composite for the tab + */ + public Control getControl() + { + return null; + } + + public void refresh(ManagedBean mbean) + { + if (mbean == null) + { + refresh(); + } + } + + public void refresh() + { + + } + + public void refresh(ManagedBean mbean, OperationData opData) + { + + } + + /** + * Sets focus on a widget + */ + public void setFocus() + { + + } + + public boolean isSimpleType(Object data) + { + return simpleTypes.contains(data.getClass().getName()); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TreeObject.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TreeObject.java new file mode 100644 index 0000000000..9545ed9876 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TreeObject.java @@ -0,0 +1,126 @@ +/* + * + * 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 java.util.ArrayList; +import java.util.List; + +import org.apache.qpid.management.ui.Constants; +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.ManagedObject; + +public class TreeObject +{ + private String _name; + private String _type; + private String _virtualHost; + private TreeObject _parent; + private List<TreeObject> _children = new ArrayList<TreeObject>(); + private ManagedObject _object; + + public TreeObject(String name, String type) + { + this._name = name; + this._type = type; + } + + public TreeObject(ManagedObject obj) + { + _name = obj.getName(); + if (_name == null && (obj instanceof ManagedBean)) + { + String[] types = ((ManagedBean)obj).getType().split("\\."); + _name = types[types.length - 1]; + } + this._type = Constants.MBEAN; + this._object = obj; + } + + public void addChild(TreeObject child) + { + _children.add(child); + } + + public void addChildren(List<TreeObject> subList) + { + _children.addAll(subList); + } + + public List<TreeObject> getChildren() + { + return _children; + } + + public void setChildren(List<TreeObject> children) + { + this._children = children; + } + + public void setName(String value) + { + _name = value; + } + + public String getName() + { + return _name; + } + public String getType() + { + return _type; + } + + public String getVirtualHost() + { + // To make it work with the broker with no virtual host implementation + return _virtualHost == null ? Constants.DEFAULT_VH : _virtualHost; + } + + public void setVirtualHost(String vHost) + { + _virtualHost = vHost; + } + + public ManagedObject getManagedObject() + { + return _object; + } + + public void setManagedObject(ManagedObject obj) + { + this._object = obj; + } + + public TreeObject getParent() + { + return _parent; + } + + public void setParent(TreeObject parent) + { + this._parent = parent; + + if (parent != null) + { + parent.addChild(this); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java new file mode 100644 index 0000000000..d23355501f --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java @@ -0,0 +1,484 @@ +/* + * + * 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.BUTTON_CLEAR; +import static org.apache.qpid.management.ui.Constants.CONSOLE_IMAGE; +import static org.apache.qpid.management.ui.Constants.FONT_BUTTON; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ServerRegistry; +import org.apache.qpid.management.ui.model.NotificationObject; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.Form; +import org.eclipse.ui.forms.widgets.FormToolkit; + +public class VHNotificationsTabControl extends TabControl +{ + protected FormToolkit _toolkit; + protected Form _form; + protected Table _table = null; + protected TableViewer _tableViewer = null; + + protected Thread _worker = null; + protected boolean _workerRunning = false; + + protected List<NotificationObject> _notifications = null; + + private static final String COLUMN_OBJ = "Object Name"; + private static final String COLUMN_SEQ = "Sequence No"; + private static final String COLUMN_TIME = "TimeStamp"; + private static final String COLUMN_TYPE = "Type"; + private static final String COLUMN_MSG = "Notification Message"; + private static final String[] TABLE_TITLES = new String [] { + COLUMN_OBJ, + COLUMN_SEQ, + COLUMN_TIME, + COLUMN_TYPE, + COLUMN_MSG + }; + + protected Button _clearButton = null; + + public VHNotificationsTabControl(TabFolder tabFolder) + { + super(tabFolder); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createForm(_tabFolder); + GridLayout gridLayout = new GridLayout(); + gridLayout.marginWidth = 0; + gridLayout.marginHeight = 0; + _form.getBody().setLayout(gridLayout); + + createWidgets(); + } + + protected void createWidgets() + { + addButtons(); + createTableViewer(); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * Creates clear buttin and refresh button + */ + protected void addButtons() + { + Composite composite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + composite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); + composite.setLayout(new GridLayout(2,false)); + + // Add Clear Button + _clearButton = _toolkit.createButton(composite, BUTTON_CLEAR, SWT.PUSH | SWT.CENTER); + _clearButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + GridData gridData = new GridData(SWT.LEAD, SWT.TOP, true, false); + gridData.widthHint = 80; + _clearButton.setLayoutData(gridData); + _clearButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer()); + IStructuredSelection ss = (IStructuredSelection)_tableViewer.getSelection(); + if(!ss.isEmpty()) + { + //clear selected Notifications + serverRegistry.clearNotifications(null, ss.toList()); + } + else if(_notifications != null) + { + //clear all the notifications, if there are any + + //check the user is certain of this clear-all operation + int response = ViewUtility.popupOkCancelConfirmationMessage( + "Clear Notifications", "Clear all Notifications for this VirtualHost?"); + if(response != SWT.OK) + { + return; + } + + synchronized(this) + { + serverRegistry.clearNotifications(null, _notifications); + } + } + + refresh(); + } + }); + //add description + Label desc = _toolkit.createLabel(composite,"Clears the selected Notifications, or all if none are selected"); + desc.setLayoutData(new GridData(SWT.LEFT,SWT.CENTER, false, false)); + } + + /** + * Creates table to display notifications + */ + private void createTable() + { + _table = _toolkit.createTable(_form.getBody(), SWT.MULTI | SWT.FULL_SELECTION); + _table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + TableColumn column = new TableColumn(_table, SWT.NONE); + column.setText(TABLE_TITLES[0]); + column.setWidth(100); + + column = new TableColumn(_table, SWT.NONE); + column.setText(TABLE_TITLES[1]); + column.setWidth(100); + + column = new TableColumn(_table, SWT.NONE); + column.setText(TABLE_TITLES[2]); + column.setWidth(130); + + column = new TableColumn(_table, SWT.NONE); + column.setText(TABLE_TITLES[3]); + column.setWidth(100); + + column = new TableColumn(_table, SWT.NONE); + column.setText(TABLE_TITLES[4]); + column.setWidth(500); + + _table.setHeaderVisible(true); + _table.setLinesVisible(true); + } + + /** + * Creates JFace viewer for the notifications table + */ + protected void createTableViewer() + { + createTable(); + _tableViewer = new TableViewer(_table); + _tableViewer.setUseHashlookup(true); + _tableViewer.setContentProvider(new ContentProviderImpl()); + _tableViewer.setLabelProvider(new LabelProviderImpl()); + _tableViewer.setColumnProperties(TABLE_TITLES); + + addTableListeners(); + } + + /** + * Adds listeners to the viewer for displaying notification details + */ + protected void addTableListeners() + { + _tableViewer.addDoubleClickListener(new IDoubleClickListener() + { + Display display = null; + Shell shell = null; + public void doubleClick(DoubleClickEvent event) + { + display = Display.getCurrent(); + shell = new Shell(display, SWT.BORDER | SWT.CLOSE | SWT.MIN | SWT.MAX | SWT.RESIZE); + shell.setText("Notification"); + shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE)); + + int x = display.getBounds().width; + int y = display.getBounds().height; + shell.setBounds(x/4, y/4, x/2, y/3); + StructuredSelection selection = (StructuredSelection)event.getSelection(); + createPopupContents((NotificationObject)selection.getFirstElement()); + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + + //If you create it, you dispose it. + shell.dispose(); + } + + private void createPopupContents(NotificationObject obj) + { + shell.setLayout(new GridLayout()); + + Composite parent = _toolkit.createComposite(shell, SWT.NONE); + parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + GridLayout layout = new GridLayout(4, true); + parent.setLayout(layout); + + // Object name record + Label key = _toolkit.createLabel(parent, COLUMN_OBJ, SWT.TRAIL); + GridData layoutData = new GridData(SWT.TRAIL, SWT.TOP, false, false,1,1); + key.setLayoutData(layoutData); + Text value = _toolkit.createText(parent, obj.getSourceName(), SWT.BEGINNING | SWT.BORDER |SWT.READ_ONLY); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); + + // Sequence no record + key = _toolkit.createLabel(parent, COLUMN_SEQ, SWT.TRAIL); + layoutData = new GridData(SWT.TRAIL, SWT.TOP, false, false,1,1); + key.setLayoutData(layoutData); + value = _toolkit.createText(parent, ""+obj.getSequenceNo(), SWT.BEGINNING | SWT.BORDER |SWT.READ_ONLY); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); + + // Time row + key = _toolkit.createLabel(parent, COLUMN_TIME, SWT.TRAIL); + key.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, true, false,1,1)); + value = _toolkit.createText(parent, obj.getTimeStamp(), SWT.BEGINNING | SWT.BORDER | SWT.READ_ONLY); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); + + key = _toolkit.createLabel(parent, COLUMN_TYPE, SWT.TRAIL); + key.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, true, false,1,1)); + value = _toolkit.createText(parent, obj.getType(), SWT.BEGINNING | SWT.BORDER | SWT.READ_ONLY); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); + + key = _toolkit.createLabel(parent, COLUMN_MSG, SWT.TRAIL); + key.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, true, false,1,1)); + value = _toolkit.createText(parent, obj.getMessage(), SWT.MULTI | SWT.WRAP| SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1); + gridData.heightHint = 100; + value.setLayoutData(gridData); + } + }); + } + + public void refresh() + { + if(_workerRunning) + { + //perform an single immediate-update + updateTableViewer(); + } + else + { + //start a worker to do the update and keep going as required + _workerRunning = true; + _worker = new Thread(new Worker()); + _worker.start(); + } + + _form.layout(true); + _form.getBody().layout(true, true); + } + + /** + * Content provider class for the table viewer + */ + protected class ContentProviderImpl implements IStructuredContentProvider, INotificationViewer + { + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + public void dispose() + { + + } + public Object[] getElements(Object parent) + { + synchronized(VHNotificationsTabControl.this) + { + return _notifications.toArray(new NotificationObject[0]); + } + } + public void addNotification(NotificationObject notification) + { + _tableViewer.add(notification); + } + + public void addNotification(List<NotificationObject> notificationList) + { + _tableViewer.add(notificationList.toArray(new NotificationObject[0])); + } + } + + /** + * Label provider for the table viewer + */ + protected static class LabelProviderImpl implements ITableLabelProvider + { + List<ILabelProviderListener> listeners = new ArrayList<ILabelProviderListener>(); + public void addListener(ILabelProviderListener listener) + { + listeners.add(listener); + } + + public void dispose(){ + + } + + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + public String getColumnText(Object element, int columnIndex) + { + String result = null; + NotificationObject t = (NotificationObject)element; + switch(columnIndex) + { + case 0 : + result = t.getSourceName(); + break; + case 1 : + result = String.valueOf(t.getSequenceNo()); + break; + case 2 : + result = String.valueOf(t.getTimeStamp()); + break; + case 3 : + result = t.getType(); + break; + case 4 : + result = t.getMessage(); + break; + default : + result = ""; + } + + return result; + } + + public boolean isLabelProperty(Object element, String property) + { + return false; + } + + public void removeListener(ILabelProviderListener listener) + { + listeners.remove(listener); + } + } // end of LabelProviderImpl + + + protected void setWorkerRunning(boolean running) + { + _workerRunning = running; + } + + /** + * Worker class which keeps looking if there are new notifications coming from server for the selected mbean + */ + private class Worker implements Runnable + { + private boolean keepGoing = true; + + public void run() + { + final Display display = _tabFolder.getDisplay(); + + while(keepGoing) + { + if (display == null || display.isDisposed()) + { + setWorkerRunning(false); + break; //stop the thread + } + + display.syncExec(new Runnable() + { + public void run() + { + if (_form == null || _form.isDisposed()) + { + setWorkerRunning(false); + keepGoing = false; //exit the loop and stop the thread + } + else + { + keepGoing = _form.isVisible(); + setWorkerRunning(keepGoing); + } + + if (keepGoing) + { + updateTableViewer(); + } + } + }); + + if (keepGoing) + { + sleep(); + } + } + } + + private void sleep() + { + try + { + Thread.sleep(2000); + } + catch(Exception ex) + { + + } + } + } + + /** + * Updates the table with new notifications received from mbean server for all mbeans in this virtual host + */ + protected void updateTableViewer() + { + String virtualhost = MBeanView.getVirtualHost(); + + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer()); + List<NotificationObject> newList = serverRegistry.getNotifications(virtualhost); + + synchronized(this) + { + _notifications = newList; + _tableViewer.setInput(_notifications); + } + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java new file mode 100644 index 0000000000..8e4bea39e9 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java @@ -0,0 +1,1032 @@ +/* + * + * 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 java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import org.apache.commons.codec.binary.Hex; +import org.apache.qpid.management.ui.ApplicationRegistry; +import static org.apache.qpid.management.ui.Constants.FAILURE_IMAGE; +import static org.apache.qpid.management.ui.Constants.SUCCESS_IMAGE; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +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.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.FormToolkit; + +/** + * Utility Class for displaying OpenMbean data types by creating required SWT widgets + */ +public class ViewUtility +{ + public static final String OP_NAME = "operation_name"; + public static final String OP_PARAMS = "parameters"; + public static final String PARAMS_TEXT = "text"; + + public static final String FIRST = "First"; + public static final String LAST = "Last"; + public static final String NEXT = "Next"; + public static final String PREV = "Previous"; + public static final String INDEX = "Index"; + + private static final Comparator tabularDataComparator = new TabularDataComparator(); + + private static MBeanView _mbeanView = null; + + private static List<String> SUPPORTED_ARRAY_DATATYPES = new ArrayList<String>(); + static + { + SUPPORTED_ARRAY_DATATYPES.add("java.lang.String"); + SUPPORTED_ARRAY_DATATYPES.add("java.lang.Boolean"); + SUPPORTED_ARRAY_DATATYPES.add("java.lang.Character"); + SUPPORTED_ARRAY_DATATYPES.add("java.lang.Integer"); + SUPPORTED_ARRAY_DATATYPES.add("java.lang.Long"); + SUPPORTED_ARRAY_DATATYPES.add("java.lang.Double"); + SUPPORTED_ARRAY_DATATYPES.add("java.util.Date"); + } + + private static final int DEFAULT_CONTENT_SIZE = 198; + static Button _firstButton, _nextButton, _previousButton, _lastButton; + static Text _hexNumTextToEnd, _hexNumTextToStart; + + /** + * Populates the composite with given openmbean data type (TabularType or CompositeType) + * @param toolkit + * @param parent composite + * @param data open mbean data type(either composite type or tabular data type) + */ + public static void populateCompositeWithData(FormToolkit toolkit, Composite parent, Object data) + { + if (data instanceof TabularDataSupport) + { + ViewUtility.createTabularDataHolder(toolkit, parent, (TabularDataSupport)data); + } + else if (data instanceof CompositeDataSupport) + { + ViewUtility.populateCompositeWithCompositeData(toolkit, parent, (CompositeDataSupport)data); + } + } + + @SuppressWarnings("unchecked") + private static void createTabularDataHolder(FormToolkit toolkit, Composite parent, TabularDataSupport tabularData) + { + Composite composite = toolkit.createComposite(parent, SWT.BORDER); + GridLayout layout = new GridLayout(4, true); + layout.horizontalSpacing = 0; + layout.marginWidth = 0; + layout.marginHeight = 10; + layout.verticalSpacing = 10; + composite.setLayout(layout); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + Set entrySet = tabularData.entrySet(); + ArrayList<Map.Entry> list = new ArrayList<Map.Entry>(entrySet); + if (list.size() == 0) + { + Text text = toolkit.createText(composite, " No records ", SWT.CENTER | SWT.SINGLE | SWT.READ_ONLY); + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1); + text.setLayoutData(layoutData); + return; + } + + Collections.sort(list, tabularDataComparator); + + // Attach the tabular record to be retrieved and shown later when record is traversed + // using first/next/previous/last buttons + composite.setData(list); + + // Create button and the composite for CompositeData + Composite compositeDataHolder = createCompositeDataHolder(toolkit, composite, + tabularData.getTabularType().getRowType()); + + // display the first record + CompositeData data = (CompositeData)(list.get(0)).getValue(); + composite.setData(INDEX, 0); + populateCompositeWithCompositeData(toolkit, compositeDataHolder, data); + enableOrDisableTraversalButtons(composite); + } + + private static void enableOrDisableTraversalButtons(Composite composite) + { + int index = (Integer)composite.getData(INDEX); + int size = ((List)composite.getData()).size(); + + ((Button)composite.getData(FIRST)).setEnabled(true); + ((Button)composite.getData(PREV)).setEnabled(true); + ((Button)composite.getData(NEXT)).setEnabled(true); + ((Button)composite.getData(LAST)).setEnabled(true); + + if (index == 0) + { + ((Button)composite.getData(FIRST)).setEnabled(false); + ((Button)composite.getData(PREV)).setEnabled(false); + } + if (index == size -1) + { + ((Button)composite.getData(NEXT)).setEnabled(false); + ((Button)composite.getData(LAST)).setEnabled(false); + } + } + + /** + * Sets up the given composite for holding a CompositeData. Create traversal buttons, label etc and + * creates a child Composite, which should be populated with the CompositeData + * @param toolkit + * @param dataHolder + * @param compositeType + * @return + */ + private static Composite createCompositeDataHolder(final FormToolkit toolkit, final Composite dataHolder, CompositeType compositeType) + { + String desc = compositeType.getDescription(); + Label description = toolkit.createLabel(dataHolder, desc, SWT.CENTER); + description.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false, 4, 1)); + // TODO nameLabel.setFont(font); + description.setText(desc); + + // Add traversal buttons + final Button firstRecordButton = toolkit.createButton(dataHolder, FIRST, SWT.PUSH); + GridData layoutData = new GridData (GridData.HORIZONTAL_ALIGN_END); + layoutData.widthHint = 80; + firstRecordButton.setLayoutData(layoutData); + + final Button previousRecordButton = toolkit.createButton(dataHolder, PREV, SWT.PUSH); + layoutData = new GridData (GridData.HORIZONTAL_ALIGN_END); + layoutData.widthHint = 80; + previousRecordButton.setLayoutData(layoutData); + + final Button nextRecordButton = toolkit.createButton(dataHolder, NEXT, SWT.PUSH); + layoutData = new GridData (GridData.HORIZONTAL_ALIGN_BEGINNING); + layoutData.widthHint = 80; + nextRecordButton.setLayoutData(layoutData); + + final Button lastRecordButton = toolkit.createButton(dataHolder, LAST, SWT.PUSH); + layoutData = new GridData (GridData.HORIZONTAL_ALIGN_BEGINNING); + layoutData.widthHint = 80; + lastRecordButton.setLayoutData(layoutData); + + // Now create the composite, which will hold the CompositeData + final Composite composite = toolkit.createComposite(dataHolder, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.horizontalSpacing = layout.verticalSpacing = 0; + layout.marginHeight = layout.marginWidth = 0; + composite.setLayout(layout); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1)); + + // Add button references. These references will be used when buttons + // are to enabled or disabled based of record index. e.g. for first record + // First and Previous buttons will be disabled. + dataHolder.setData(FIRST, firstRecordButton); + dataHolder.setData(NEXT, nextRecordButton); + dataHolder.setData(PREV, previousRecordButton); + dataHolder.setData(LAST, lastRecordButton); + + // Listener for the traversal buttons. When a button is clicked the respective + // CompositeData will be populated in the composite + SelectionListener listener = new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + if (!(e.widget instanceof Button)) + return; + + Button traverseButton =(Button)e.widget; + // Get the CompositeData respective to the button selected + CompositeData data = getCompositeData(dataHolder, traverseButton.getText()); + populateCompositeWithCompositeData(toolkit, composite, data); + enableOrDisableTraversalButtons(dataHolder); + } + }; + + firstRecordButton.addSelectionListener(listener); + nextRecordButton.addSelectionListener(listener); + previousRecordButton.addSelectionListener(listener); + lastRecordButton.addSelectionListener(listener); + + return composite; + } + + /** + * The CompositeData is set as data with the Composite and using the index, this method will + * return the corresponding CompositeData + * @param compositeHolder + * @param dataIndex + * @return the CompositeData respective to the index + */ + private static CompositeData getCompositeData(Composite compositeHolder, String dataIndex) + { + List objectData = (List)compositeHolder.getData(); + if (objectData == null || objectData.isEmpty()) + { + // TODO + } + + // Get the index of record to be shown. + int index = 0; + if (compositeHolder.getData(INDEX) != null) + { + index = (Integer)compositeHolder.getData(INDEX); + } + + if (FIRST.equals(dataIndex)) + { + index = 0; + } + else if (NEXT.equals(dataIndex)) + { + index = index + 1; + } + else if (PREV.equals(dataIndex)) + { + index = (index != 0) ? (index = index - 1) : index; + } + else if (LAST.equals(dataIndex)) + { + index = objectData.size() -1; + } + + // Set the index being shown. + compositeHolder.setData(INDEX, index); + + return (CompositeData)((Map.Entry)objectData.get(index)).getValue(); + } + + /** + * Populates the given composite with the CompositeData. Creates required widgets to hold the data types + * @param toolkit + * @param parent + * @param data CompositeData + */ + @SuppressWarnings("unchecked") + private static void populateCompositeWithCompositeData(FormToolkit toolkit, Composite parent, CompositeData data) + { + Control[] oldControls = parent.getChildren(); + for (int i = 0; i < oldControls.length; i++) + { + oldControls[i].dispose(); + } + + Composite compositeHolder = toolkit.createComposite(parent, SWT.NONE); + GridLayout layout = new GridLayout(4, false); + layout.horizontalSpacing = 10; + compositeHolder.setLayout(layout); + compositeHolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + + // ItemNames in composite data + List<String> itemNames = new ArrayList<String>(data.getCompositeType().keySet()); + + for (String itemName : itemNames) + { + OpenType itemType = data.getCompositeType().getType(itemName); + Label keyLabel = toolkit.createLabel(compositeHolder, itemName, SWT.TRAIL); + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1); + layoutData.minimumWidth = 70; + keyLabel.setLayoutData(layoutData); + + if (itemType.isArray()) + { + OpenType type = ((ArrayType)itemType).getElementOpenType(); + // If Byte array and mimetype is text, convert to text string + if (type.getClassName().equals(Byte.class.getName())) + { + String mimeType = null; + String encoding = null; + if (data.containsKey("MimeType")) + { + mimeType = (String)data.get("MimeType"); + } + if (data.containsKey("Encoding")) + { + encoding = (String)data.get("Encoding"); + } + + if (encoding == null || encoding.length() == 0) + { + encoding = Charset.defaultCharset().name(); + } + + if ("text/plain".equals(mimeType)) + { + convertByteArray(toolkit, compositeHolder, data, itemName, encoding); + } + else + { + handleBinaryMessageContent(toolkit, compositeHolder, data, itemName, encoding); + } + } + // If array of any other supported type, show as a list of String array + else if (SUPPORTED_ARRAY_DATATYPES.contains(type.getClassName())) + { + convertArrayItemForDisplay(compositeHolder, data, itemName); + } + else + { + setNotSupportedDataType(toolkit, compositeHolder); + } + } + else if (itemType instanceof TabularType) + { + Composite composite = toolkit.createComposite(compositeHolder, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1)); + layout = new GridLayout(); + layout.marginHeight = 0; + layout.marginWidth = 0; + composite.setLayout(layout); + createTabularDataHolder(toolkit, composite, (TabularDataSupport)data.get(itemName)); + } + else + { + Text valueText = toolkit.createText(compositeHolder, String.valueOf(data.get(itemName)), SWT.READ_ONLY | SWT.BORDER); + valueText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1)); + } + } + + // layout the composite after creating new widgets. + parent.layout(); + } //end of method + + + private static void convertByteArray(FormToolkit toolkit, Composite compositeHolder, CompositeData data, String itemName, String encoding) + { + Byte[] arrayItems = (Byte[])data.get(itemName); + byte[] byteArray = new byte[arrayItems.length]; + + for (int i = 0; i < arrayItems.length; i++) + { + byteArray[i] = arrayItems[i]; + } + try + { + String textMessage = new String(byteArray, encoding); + + Text valueText = toolkit.createText(compositeHolder, textMessage, SWT.READ_ONLY | SWT.BORDER | + SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1); + gridData.heightHint = 300; + valueText.setLayoutData(gridData); + } + catch(Exception ex) + { + ex.printStackTrace(); + } + } + + private static Shell getShell() + { + Shell shell = Display.getCurrent().getActiveShell(); + + // Under linux GTK getActiveShell returns null so we need to make a new shell for display. + // Under windows this is fine. + if (shell == null) + { + // This occurs under linux gtk + shell = new Shell(Display.getCurrent(), SWT.BORDER | SWT.CLOSE | SWT.MIN | SWT.MAX); + } + + return shell; + } + + private static int showBox(String title, String message, int icon) + { + MessageBox messageBox = new MessageBox(getShell(), icon); + messageBox.setMessage(message); + messageBox.setText(title); + + return messageBox.open(); + } + + /** + * Creates widgets for object messages and populates the content in hexadecimal format. + * @param toolkit + * @param compositeHolder + * @param data + * @param itemName + * @param encoding + */ + private static void handleBinaryMessageContent(FormToolkit toolkit, Composite compositeHolder, CompositeData data, String itemName, String encoding) + { + final String thisEncoding = encoding; + final Byte[] arrayItems = (Byte[]) data.get(itemName); + final byte[] byteArray = new byte[arrayItems.length]; + + for (int i = 0; i < arrayItems.length; i++) + { + byteArray[i] = arrayItems[i]; + } + + try + { + //create a new composite to contain the widgets required to display object messages. + final Composite localComposite = toolkit.createComposite(compositeHolder, SWT.NONE); + localComposite.setData("currentBytePos", 0); + localComposite.setData("startingBytePos", 0); + GridLayout layout = new GridLayout(2, true); + layout.marginWidth = 0; + layout.marginHeight = 0; + localComposite.setLayout(layout); + localComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); + + int startContentSize = DEFAULT_CONTENT_SIZE; + + if (byteArray.length < DEFAULT_CONTENT_SIZE) + { + startContentSize = byteArray.length; + } + + //create a text to display the hexadecimal views of object messages, it takes more space than ascii view as + //a hex uses 2 chars and 1 space, while ascii only uses 1 char and 1 space. + final Text hexText = toolkit.createText(localComposite, + displayByteFormat(localComposite, byteArray, startContentSize * 2, thisEncoding, "<<", true), + SWT.READ_ONLY | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.BORDER); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); + gridData.widthHint = 144; //set to 222 if not using any fonts + gridData.heightHint = 200; + hexText.setLayoutData(gridData); + + final Text asciiText = toolkit.createText(localComposite, + displayByteFormat(localComposite, byteArray, startContentSize * 2, thisEncoding, "<<", false), + SWT.READ_ONLY | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.BORDER); + + + gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); + gridData.widthHint = 52;//set to 98 if not using any fonts + gridData.heightHint = 200; + asciiText.setLayoutData(gridData); + + //use a monospaced font for a better layout + Font font = new Font(compositeHolder.getDisplay(), "Courier", 10, SWT.NORMAL); + hexText.setFont(font); + asciiText.setFont(font); + + final ScrollBar hexScrollBar = hexText.getVerticalBar(); + final ScrollBar asciiScrollBar = asciiText.getVerticalBar(); + + //create a sub composite to contain all the buttons + final Composite buttonComposite = toolkit.createComposite(localComposite, SWT.NONE); + layout = new GridLayout(7, false); + layout.marginWidth = 0; + buttonComposite.setLayout(layout); + buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); + + _firstButton = toolkit.createButton(buttonComposite, "<<", SWT.PUSH); + GridData layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + layoutData.widthHint = 40; + _firstButton.setLayoutData(layoutData); + _firstButton.setToolTipText("See the first n bytes"); + + _previousButton = toolkit.createButton(buttonComposite, "<", SWT.PUSH); + layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + layoutData.widthHint = 40; + _previousButton.setLayoutData(layoutData); + _previousButton.setToolTipText("See the previous n bytes"); + _previousButton.setEnabled(false); + + _hexNumTextToStart = toolkit.createText(buttonComposite, "0"); + layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + layoutData.widthHint = 40; + _hexNumTextToStart.setLayoutData(layoutData); + _hexNumTextToStart.setEditable(false); + + final Text hexNumText = toolkit.createText(buttonComposite, "" + startContentSize); + layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + layoutData.widthHint = 40; + hexNumText.setLayoutData(layoutData); + + _hexNumTextToEnd = toolkit.createText(buttonComposite, "" + (byteArray.length - startContentSize)); + layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + layoutData.widthHint = 40; + _hexNumTextToEnd.setLayoutData(layoutData); + _hexNumTextToEnd.setEditable(false); + + _nextButton = toolkit.createButton(buttonComposite, ">", SWT.PUSH); + layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + layoutData.widthHint = 40; + _nextButton.setLayoutData(layoutData); + _nextButton.setToolTipText("See the next n bytes"); + _nextButton.setEnabled(true); + + _lastButton = toolkit.createButton(buttonComposite, ">>", SWT.PUSH); + layoutData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + layoutData.widthHint = 40; + _lastButton.setToolTipText("See the last n bytes"); + _lastButton.setLayoutData(layoutData); + + SelectionListener listener = new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + if (e.widget instanceof Button) + { + String numOfBytes = hexNumText.getText(); + try + { + int n = Integer.parseInt(numOfBytes); + + //Reset range display if user requests a large value + if (n > byteArray.length) + { + n = (byteArray.length > DEFAULT_CONTENT_SIZE) ? DEFAULT_CONTENT_SIZE : byteArray.length; + hexNumText.setText("" + n); + } + + //rest if the user requests 0 + if (n < 1) + { + n = DEFAULT_CONTENT_SIZE; + hexNumText.setText("" + n); + } + + Button button = (Button) e.widget; + hexText.setText(displayByteFormat(localComposite, byteArray, n * 2, thisEncoding, + button.getText(), true)); + asciiText.setText(displayByteFormat(localComposite, byteArray, n * 2, thisEncoding, + button.getText(), false)); + } + catch (NumberFormatException exp) + { + popupErrorMessage("Error", "Please input the number of bytes you wish to look at"); + } + } + if (e.widget instanceof ScrollBar) + { + //synchronize the movements of the two scrollbars + ScrollBar sb = (ScrollBar) e.widget; + if (sb.getParent().equals(hexText)) + { + asciiScrollBar.setIncrement(sb.getIncrement()); + asciiScrollBar.setSelection(sb.getSelection()); + } + else if (sb.getParent().equals(asciiText)) + { + hexScrollBar.setSelection(sb.getSelection()); + hexScrollBar.setIncrement(sb.getIncrement()); + } + } + } + }; + localComposite.addControlListener(new ControlAdapter() + { + public void controlResized(ControlEvent e) + { + //if the control is resized, set different parameters to make a single line displays the same contents. + if (((GridLayout) localComposite.getLayout()).makeColumnsEqualWidth) + { + ((GridLayout) localComposite.getLayout()).makeColumnsEqualWidth = false; + ((GridLayout) localComposite.getLayout()).numColumns = 2; + ((GridData) hexText.getLayoutData()).horizontalSpan = 1; + ((GridData) hexText.getLayoutData()).widthHint = 144; + ((GridData) asciiText.getLayoutData()).horizontalSpan = 1; + ((GridData) asciiText.getLayoutData()).widthHint = 52; + ((GridData) buttonComposite.getLayoutData()).horizontalSpan = 2; + } + else + { + ((GridLayout) localComposite.getLayout()).makeColumnsEqualWidth = true; + ((GridLayout) localComposite.getLayout()).numColumns = 42; //set to 47 if not using any fonts + ((GridData) hexText.getLayoutData()).horizontalSpan = 25; // set to 30 if not using any fonts + ((GridData) asciiText.getLayoutData()).horizontalSpan = 17; // set to 17 if not using any fonts + ((GridData) buttonComposite.getLayoutData()).horizontalSpan = 42; + } + } + }); + + _firstButton.addSelectionListener(listener); + _previousButton.addSelectionListener(listener); + _nextButton.addSelectionListener(listener); + _lastButton.addSelectionListener(listener); + hexScrollBar.addSelectionListener(listener); + asciiScrollBar.addSelectionListener(listener); + //f.dispose(); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + + /** + * Format object messages to have a hexadecimal view and a ascii view. + * @param numOfBytes + * @param encoding + * @return + */ + private static String displayByteFormat(Composite localComposite, byte[] byteArray, int numOfBytes, + String encoding, String direction, boolean isHex) + { + final Hex hexeconder = new Hex(); + final byte[] encoded = hexeconder.encode(byteArray); + + int hexLength = byteArray.length * 2; + StringBuilder sb = new StringBuilder(); + int currentBytePos = (Integer) localComposite.getData("currentBytePos"); + int startingBytePos = (Integer) localComposite.getData("startingBytePos"); + + int strLength = 0; + int offset = 0; + String encStr; + if (isHex) + { + if (direction.equals("<<")) + { + strLength = (numOfBytes > hexLength) ? hexLength : numOfBytes; + offset = 0; + } + else if (direction.equals("<")) + { + strLength = (startingBytePos - numOfBytes < 0) ? startingBytePos : numOfBytes; + offset = (startingBytePos - numOfBytes < 0) ? 0 : startingBytePos - numOfBytes; + } + else if (direction.equals(">")) + { + strLength = (numOfBytes > (hexLength - currentBytePos)) ? hexLength - currentBytePos : numOfBytes; + offset = currentBytePos; + } + else if (direction.equals(">>")) + { + strLength = (numOfBytes > hexLength) ? hexLength : numOfBytes; + offset = (hexLength - numOfBytes > 0) ? hexLength - numOfBytes : 0; + } + else + { + strLength = hexLength; + offset = 0; + } + localComposite.setData("strLength", strLength); + localComposite.setData("currentBytePos", offset + strLength); + localComposite.setData("startingBytePos", offset); + + if (_lastButton != null && !_lastButton.isDisposed()) + { + //Set button state + _previousButton.setEnabled(offset != 0); + _nextButton.setEnabled(offset + strLength != hexLength); + + //set the text fields + _hexNumTextToStart.setText("" + offset / 2); + _hexNumTextToEnd.setText("" + (hexLength - (offset + strLength)) / 2); + } + } + + try + { + if (isHex) + { + encStr = new String(encoded, offset, strLength, encoding); + for (int c = 0; c < strLength; c++) + { + sb.append(encStr.charAt(c)); + if (c % 2 == 1) + { + sb.append(" "); + } + } + return sb.toString().toUpperCase(); + } + else + { + strLength = (Integer) localComposite.getData("strLength"); + sb = new StringBuilder(); + encStr = new String(byteArray, startingBytePos / 2, strLength / 2, encoding); + for (int c = 0; c < encStr.length(); c++) + { + char ch = encStr.charAt(c); + if (ch > 31 && ch < 127) + { + sb.append(ch); + } + else + { + sb.append("?"); + } + + sb.append(" "); + } + } + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + return sb.toString(); + } + + public static int popupInfoMessage(String title, String message) + { + return showBox(title, message, SWT.ICON_INFORMATION | SWT.OK); + } + + public static int popupErrorMessage(String title, String message) + { + return showBox(title, message, SWT.ICON_ERROR | SWT.OK); + } + + public static int popupConfirmationMessage(String title, String message) + { + return showBox(title, message,SWT.ICON_QUESTION | SWT.YES | SWT.NO); + } + + public static int popupOkCancelConfirmationMessage(String title, String message) + { + return showBox(title, message,SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL); + } + + + public static Shell createPopupShell(String title, int width, int height) + { + Display display = Display.getCurrent(); + final Shell shell = new Shell(display, SWT.BORDER | SWT.CLOSE | SWT.MIN |SWT.MAX); + shell.setText(title); + shell.setLayout(new GridLayout()); + int x = display.getBounds().width; + int y = display.getBounds().height; + shell.setBounds(x/4, y/4, width, height); + + shell.addListener(SWT.Traverse, new Listener () { + public void handleEvent (Event event) { + switch (event.detail) { + case SWT.TRAVERSE_ESCAPE: + shell.close (); + event.detail = SWT.TRAVERSE_NONE; + event.doit = false; + break; + } + } + }); + + return shell; + } + + public static Shell createModalDialogShell(Shell parent, String title) + { + final Shell shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); + shell.setText(title); + shell.setLayout(new GridLayout()); + + shell.addListener(SWT.Traverse, new Listener () { + public void handleEvent (Event event) { + switch (event.detail) { + case SWT.TRAVERSE_ESCAPE: + shell.close (); + event.detail = SWT.TRAVERSE_NONE; + event.doit = false; + break; + } + } + }); + + return shell; + } + + /** + * Creates a List widget for displaying array of strings + * @param compositeHolder + * @param data - containing the array item value + * @param itemName - item name + */ + private static void convertArrayItemForDisplay(Composite compositeHolder, CompositeData data, String itemName) + { + Object[] arrayItems = (Object[])data.get(itemName); + String[] items = new String[arrayItems.length]; + for (int i = 0; i < arrayItems.length; i++) + { + items[i] = String.valueOf(arrayItems[i]); + } + org.eclipse.swt.widgets.List list = new org.eclipse.swt.widgets.List(compositeHolder, + SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY); + list.setItems(items); + //list.setBackground(compositeHolder.getBackground()); + list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); + } + + private static void setNotSupportedDataType(FormToolkit toolkit, Composite compositeHolder) + { + Text valueText = toolkit.createText(compositeHolder, "--- Content can not be displayed ---", SWT.READ_ONLY); + valueText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1)); + } + + /** + * Converts the input string to displayable format by converting some character case or inserting space + * @param input + * @return formatted string + */ + public static String getDisplayText(String input) + { + StringBuffer result = new StringBuffer(input); + if (Character.isLowerCase(result.charAt(0))) + { + result.setCharAt(0, Character.toUpperCase(result.charAt(0))); + } + for (int i = 1; i < input.length(); i++) + { + if (Character.isUpperCase(result.charAt(i)) && !Character.isWhitespace(result.charAt(i - 1)) + && Character.isLowerCase(result.charAt(i - 1))) + { + result.insert(i, " "); + i++; + } + else if (Character.isLowerCase(result.charAt(i)) && Character.isWhitespace(result.charAt(i - 1))) + { + result.setCharAt(i, Character.toUpperCase(result.charAt(i))); + } + + } + + return result.toString(); + } + + /** + * Disposes the children of given Composite if not null and not already disposed + * @param parent composite + */ + public static void disposeChildren(Composite parent) + { + if (parent == null || parent.isDisposed()) + return; + + Control[] oldControls = parent.getChildren(); + for (int i = 0; i < oldControls.length; i++) + { + oldControls[i].dispose(); + } + } + + public static char[] getHash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + byte[] data = text.getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + char[] hash = new char[digest.length ]; + + int index = 0; + for (byte b : digest) + { + hash[index++] = (char) b; + } + + return hash; + } + + private static class TabularDataComparator implements java.util.Comparator<Map.Entry> + { + public int compare(Map.Entry data1, Map.Entry data2) + { + if (data1.getKey() instanceof List) + { + Object obj1 = ((List)data1.getKey()).get(0); + Object obj2 = ((List)data2.getKey()).get(0); + String str1 = obj1.toString(); + String str2 = obj2.toString(); + if (obj1 instanceof String) + { + return str1.compareTo(str2); + } + + try + { + return Long.valueOf(str1).compareTo(Long.valueOf(str2)); + } + catch (Exception ex) + { + return -1; + } + } + + return -1; + } + } + + public static void setMBeanView(MBeanView mbeanView) + { + _mbeanView = mbeanView; + } + + /** + * Report feedback for the operation + * @param result true if success, false if unsuccessful, null if invoked but void result type. + * @param successMessage + * @param failureMessage + */ + public static void operationResultFeedback(Boolean result, String successMessage, String failureMessage) + { + Image icon; + + if(_mbeanView != null) + { + if(result == null) + { + icon = ApplicationRegistry.getImage(SUCCESS_IMAGE); + _mbeanView.populateStatusBar(icon, successMessage); + } + else if(result) + { + icon = ApplicationRegistry.getImage(SUCCESS_IMAGE); + _mbeanView.populateStatusBar(icon, successMessage); + } + else + { + icon = ApplicationRegistry.getImage(FAILURE_IMAGE); + _mbeanView.populateStatusBar(icon, failureMessage); + popupErrorMessage("Operation Failed", failureMessage); + } + } + } + + public static void operationFailedStatusBarMessage(String failureMessage) + { + Image icon = ApplicationRegistry.getImage(FAILURE_IMAGE); + + if(_mbeanView != null) + { + _mbeanView.populateStatusBar(icon, failureMessage); + } + } + + public static void clearStatusBar() + { + if(_mbeanView != null) + { + _mbeanView.clearStatusBar(); + } + } + + public static void centerChildInParentShell(Shell parent, Shell child) + { + //get current parent shell size and location + int parentLocX = parent.getBounds().x; + int parentLocY = parent.getBounds().y; + int parentWidth = parent.getBounds().width; + int parentHeight = parent.getBounds().height; + + //get current child size + int childWidth = child.getSize().x; + int childHeight = child.getSize().y; + + //centre the child within/over the parent + child.setBounds((parentWidth - childWidth)/2 + parentLocX, + (parentHeight - childHeight)/2 + parentLocY, + childWidth, childHeight); + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/connection/ConnectionOperationsTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/connection/ConnectionOperationsTabControl.java new file mode 100644 index 0000000000..35171773ad --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/connection/ConnectionOperationsTabControl.java @@ -0,0 +1,545 @@ +/* + * + * 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.connection; + +import static org.apache.qpid.management.common.mbeans.ManagedConnection.CHAN_ID; +import static org.apache.qpid.management.common.mbeans.ManagedConnection.DEFAULT_QUEUE; +import static org.apache.qpid.management.common.mbeans.ManagedConnection.FLOW_BLOCKED; +import static org.apache.qpid.management.common.mbeans.ManagedConnection.TRANSACTIONAL; +import static org.apache.qpid.management.common.mbeans.ManagedConnection.UNACKED_COUNT; + +import java.util.Collection; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.TabularDataSupport; + +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.ServerRegistry; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.MBeanView; +import org.apache.qpid.management.ui.views.TabControl; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.widgets.Form; +import org.eclipse.ui.forms.widgets.FormToolkit; + + +/** + * Control class for the Connection mbean Operations tab. + */ +public class ConnectionOperationsTabControl extends TabControl +{ + private FormToolkit _toolkit; + private Form _form; + private Table _table = null; + private TableViewer _tableViewer = null; + private Composite _paramsComposite = null; + + private TabularDataSupport _channels = null; + private ManagedConnection _cmb; + private ApiVersion _ApiVersion; + + public ConnectionOperationsTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc) + { + super(tabFolder); + _mbean = mbean; + _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion(); + _cmb = (ManagedConnection) MBeanServerInvocationHandler.newProxyInstance(mbsc, + mbean.getObjectName(), ManagedConnection.class, false); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + createComposites(); + createWidgets(); + } + + private void createComposites() + { + _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + _paramsComposite.setLayout(new GridLayout()); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + _table.setFocus(); + } + + @Override + public void refresh(ManagedBean mbean) + { + _channels = null; + try + { + //gather a list of all channels on the connection for display and selection + _channels = (TabularDataSupport) _cmb.channels(); + } + catch (Exception e) + { + MBeanUtility.handleException(mbean,e); + } + + _tableViewer.setInput(_channels); + + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + private void createWidgets() + { + Group viewChannelsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE); + viewChannelsGroup.setBackground(_paramsComposite.getBackground()); + viewChannelsGroup.setText("Channels"); + viewChannelsGroup.setLayout(new GridLayout()); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.heightHint = 250; + gridData.minimumHeight = 250; + + viewChannelsGroup.setLayoutData(gridData); + + _table = new Table (viewChannelsGroup, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _table.setLinesVisible (true); + _table.setHeaderVisible (true); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + _table.setLayoutData(data); + + _tableViewer = new TableViewer(_table); + final TableSorter tableSorter = new TableSorter(); + + String[] titles; + if(_ApiVersion.greaterThanOrEqualTo(1, 5)) + { + titles = new String[]{"Id", "Transactional", "Num Unacked Msg", "Default Queue", "Flow Blocked"}; + } + else + { + titles = new String[]{"Id", "Transactional", "Num Unacked Msg", "Default Queue"}; + } + int[] bounds = { 50, 110, 145, 200, 110 }; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableColumn column = new TableColumn (_table, SWT.NONE); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _tableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _tableViewer.setContentProvider(new ContentProviderImpl()); + _tableViewer.setLabelProvider(new LabelProviderImpl()); + _tableViewer.setSorter(tableSorter); + _table.setSortColumn(_table.getColumn(0)); + _table.setSortDirection(SWT.UP); + + Composite buttonsComposite = _toolkit.createComposite(viewChannelsGroup); + gridData = new GridData(SWT.RIGHT, SWT.BOTTOM, false, false); + buttonsComposite.setLayoutData(gridData); + buttonsComposite.setLayout(new GridLayout(2,false)); + + final Button commitButton = _toolkit.createButton(buttonsComposite, "Commit Transactions", SWT.PUSH); + commitButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + commitButton.setEnabled(false); + commitButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + final CompositeData selectedChannel = (CompositeData)_table.getItem(selectionIndex).getData(); + Integer id = (Integer) selectedChannel.get(CHAN_ID); + + int response = ViewUtility.popupOkCancelConfirmationMessage("Commit Transactions", + "Commit transactions for channel:" + id + " ?"); + + if (response == SWT.OK) + { + try + { + _cmb.commitTransactions(id); + ViewUtility.operationResultFeedback(null, "Commited transactions", null); + } + catch (Exception e1) + { + ViewUtility.operationFailedStatusBarMessage("Error commiting transactions"); + MBeanUtility.handleException(_mbean, e1); + } + + refresh(_mbean);; + } + } + } + }); + + final Button rollbackButton = _toolkit.createButton(buttonsComposite, "Rollback Transactions", SWT.PUSH); + rollbackButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + rollbackButton.setEnabled(false); + rollbackButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + final CompositeData selectedChannel = (CompositeData)_table.getItem(selectionIndex).getData(); + Integer id = (Integer) selectedChannel.get(CHAN_ID); + + int response = ViewUtility.popupOkCancelConfirmationMessage("Rollback Transactions", + "Rollback transactions for channel:" + id + " ?"); + + if (response == SWT.OK) + { + try + { + _cmb.rollbackTransactions(id); + ViewUtility.operationResultFeedback(null, "Rolled back transactions", null); + } + catch (Exception e1) + { + ViewUtility.operationFailedStatusBarMessage("Error rolling back transactions"); + MBeanUtility.handleException(_mbean, e1); + } + + refresh(_mbean);; + } + } + + } + }); + + //listener for double clicking to open the selection mbean + _table.addMouseListener(new MouseListener() + { + // MouseListener implementation + public void mouseDoubleClick(MouseEvent event) + { + openMBean(_table); + } + + public void mouseDown(MouseEvent e){} + public void mouseUp(MouseEvent e){} + }); + + _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + final CompositeData selectedChannel = (CompositeData)_table.getItem(selectionIndex).getData(); + Boolean transactional = (Boolean) selectedChannel.get(TRANSACTIONAL); + + if(transactional) + { + rollbackButton.setEnabled(true); + commitButton.setEnabled(true); + } + else + { + rollbackButton.setEnabled(false); + commitButton.setEnabled(false); + } + } + else + { + rollbackButton.setEnabled(false); + commitButton.setEnabled(true); + } + } + }); + + Composite opsComposite = _toolkit.createComposite(_paramsComposite); + gridData = new GridData(SWT.LEFT, SWT.FILL, false, true); + opsComposite.setLayoutData(gridData); + opsComposite.setLayout(new GridLayout(3,false)); + + Group closeConnectionGroup = new Group(opsComposite, SWT.SHADOW_NONE); + closeConnectionGroup.setBackground(opsComposite.getBackground()); + closeConnectionGroup.setText("Close Connection"); + gridData = new GridData(SWT.LEFT, SWT.TOP, true, false); + closeConnectionGroup.setLayoutData(gridData); + closeConnectionGroup.setLayout(new GridLayout()); + + final Button closeConnectionButton = _toolkit.createButton(closeConnectionGroup, "Close Connection", SWT.PUSH); + closeConnectionButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int response = ViewUtility.popupOkCancelConfirmationMessage("Close Connection", + "Are you sure you wish to close the Connection?"); + + if (response == SWT.OK) + { + try + { + _cmb.closeConnection(); + } + catch (Exception e1) + { + MBeanUtility.handleException(_mbean, e1); + } + } + } + }); + } + + + /** + * Content Provider class for the table viewer + */ + private static class ContentProviderImpl implements IStructuredContentProvider + { + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + public Object[] getElements(Object parent) + { + Collection<Object> rowCollection = ((TabularDataSupport) parent).values(); + + return rowCollection.toArray(); + } + } + + /** + * Label Provider class for the table viewer + */ + private static class LabelProviderImpl extends LabelProvider implements ITableLabelProvider + { + public String getColumnText(Object element, int columnIndex) + { + switch (columnIndex) + { + case 0 : // id column + return String.valueOf(((CompositeDataSupport) element).get(CHAN_ID)); + case 1 : // transactional column + return String.valueOf(((CompositeDataSupport) element).get(TRANSACTIONAL)); + case 2 : // num unacked msgs column + return String.valueOf(((CompositeDataSupport) element).get(UNACKED_COUNT)); + case 3 : // default queue column + return String.valueOf(((CompositeDataSupport) element).get(DEFAULT_QUEUE)); + case 4 : // flow blocked column + return String.valueOf(((CompositeDataSupport) element).get(FLOW_BLOCKED)); + default : + return "-"; + } + } + + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + } + + /** + * Sorter class for the table viewer. + * + */ + public static class TableSorter extends ViewerSorter + { + private int column; + private static final int ASCENDING = 0; + private static final int DESCENDING = 1; + + private int direction = DESCENDING; + + public TableSorter() + { + this.column = 0; + direction = ASCENDING; + } + + public void setColumn(int column) + { + if (column == this.column) + { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } + else + { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + CompositeData chan1 = (CompositeData) e1; + CompositeData chan2 = (CompositeData) e2; + + int comparison = 0; + switch(column) + { + case 0: + comparison = ((Integer) chan1.get(CHAN_ID)).compareTo((Integer)chan2.get(CHAN_ID)); + break; + case 1: + comparison = String.valueOf(chan1.get(TRANSACTIONAL)).compareTo( + String.valueOf(chan2.get(TRANSACTIONAL))); + break; + case 2: + comparison = ((Long) chan1.get(UNACKED_COUNT)).compareTo((Long)chan2.get(UNACKED_COUNT)); + break; + case 3: + comparison = String.valueOf(chan1.get(DEFAULT_QUEUE)).compareTo( + String.valueOf(chan2.get(DEFAULT_QUEUE))); + break; + case 4: + comparison = String.valueOf(chan1.get(FLOW_BLOCKED)).compareTo( + String.valueOf(chan2.get(FLOW_BLOCKED))); + break; + default: + comparison = 0; + } + // If descending order, flip the direction + if(direction == DESCENDING) + { + comparison = -comparison; + } + return comparison; + } + } + + private void openMBean(Table table) + { + int selectionIndex = table.getSelectionIndex(); + + if (selectionIndex == -1) + { + return; + } + + CompositeData channelResult = (CompositeData) table.getItem(selectionIndex).getData(); + String queueName = (String) channelResult.get(DEFAULT_QUEUE); + + if(queueName == null) + { + return; + } + + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean); + ManagedBean selectedMBean = serverRegistry.getQueue(queueName, _mbean.getVirtualHostName()); + + if(selectedMBean == null) + { + ViewUtility.popupErrorMessage("Error", "Unable to retrieve the selected MBean to open it"); + return; + } + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID); + try + { + view.openMBean(selectedMBean); + } + catch (Exception ex) + { + MBeanUtility.handleException(selectedMBean, ex); + } + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/ExchangeOperationsTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/ExchangeOperationsTabControl.java new file mode 100644 index 0000000000..b51cb85427 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/ExchangeOperationsTabControl.java @@ -0,0 +1,722 @@ +/* + * + * 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.exchange; + +import static org.apache.qpid.management.common.mbeans.ManagedExchange.BINDING_KEY; +import static org.apache.qpid.management.common.mbeans.ManagedExchange.QUEUE_NAMES; +import static org.apache.qpid.management.ui.Constants.EXCHANGE_TYPE; +import static org.apache.qpid.management.ui.Constants.DIRECT_EXCHANGE; +import static org.apache.qpid.management.ui.Constants.FANOUT_EXCHANGE; +import static org.apache.qpid.management.ui.Constants.TOPIC_EXCHANGE; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.TabularDataSupport; + +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.ServerRegistry; +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.MBeanView; +import org.apache.qpid.management.ui.views.TabControl; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; + + +/** + * Control class for the Exchange mbean Operations tab. + */ +public class ExchangeOperationsTabControl extends TabControl +{ + private FormToolkit _toolkit; + private ScrolledForm _form; + private Table _keysTable = null; + private TableViewer _keysTableViewer = null; + private Table _queuesTable = null; + private TableViewer _queuesTableViewer = null; + private Composite _paramsComposite = null; + + private TabularDataSupport _bindings = null; + private ManagedExchange _emb; + private ApiVersion _ApiVersion; + + public ExchangeOperationsTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc) + { + super(tabFolder); + _mbean = mbean; + _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion(); + _emb = (ManagedExchange) MBeanServerInvocationHandler.newProxyInstance(mbsc, + mbean.getObjectName(), ManagedExchange.class, false); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createScrolledForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + createComposites(); + createWidgets(); + } + + private void createComposites() + { + _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + _paramsComposite.setLayout(new GridLayout()); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + _keysTable.setFocus(); + } + + @Override + public void refresh(ManagedBean mbean) + { + _bindings = null; + try + { + //gather a list of all keys and queues for display and selection + _bindings = (TabularDataSupport) _emb.bindings(); + } + catch (Exception e) + { + MBeanUtility.handleException(_mbean,e); + } + + _keysTableViewer.setInput(_bindings); + + //if we have a Qpid JMX API 1.3+ server + if(_ApiVersion.greaterThanOrEqualTo(1, 3)) + { + //if it is a fanout exchange + if(isFanoutExchange()) + { + //if there are any queue bindings, there is a single wildcard binding key + //auto-select it to show all the queues bound to the exchange + if (_keysTable.getItemCount() == 1) + { + _keysTable.setSelection(0); + updateQueuesTable(); + } + } + } + + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + private void createWidgets() + { + Group bindingsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE); + bindingsGroup.setBackground(_paramsComposite.getBackground()); + bindingsGroup.setText("Bindings"); + bindingsGroup.setLayout(new GridLayout(2,false)); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + bindingsGroup.setLayoutData(gridData); + + Composite tablesComposite = _toolkit.createComposite(bindingsGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.minimumHeight = 250; + gridData.heightHint = 250; + tablesComposite.setLayoutData(gridData); + tablesComposite.setLayout(new GridLayout(2,false)); + + _keysTable = new Table (tablesComposite, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _keysTable.setLinesVisible(true); + _keysTable.setHeaderVisible(true); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + _keysTable.setLayoutData(data); + + _keysTableViewer = new TableViewer(_keysTable); + final TableSorter tableSorter = new TableSorter(BINDING_KEY); + + String[] titles = {"Binding Key"}; + int[] bounds = {200}; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableColumn column = new TableColumn (_keysTable, SWT.NONE); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _keysTableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _keysTableViewer.setContentProvider(new ContentProviderImpl(BINDING_KEY)); + _keysTableViewer.setLabelProvider(new LabelProviderImpl(BINDING_KEY)); + _keysTableViewer.setSorter(tableSorter); + _keysTable.setSortColumn(_keysTable.getColumn(0)); + _keysTable.setSortDirection(SWT.UP); + + + _queuesTable = new Table (tablesComposite, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _queuesTable.setLinesVisible (true); + _queuesTable.setHeaderVisible (true); + data = new GridData(SWT.FILL, SWT.FILL, true, true); + _queuesTable.setLayoutData(data); + + _queuesTableViewer = new TableViewer(_queuesTable); + final TableSorter queuesTableSorter = new TableSorter(QUEUE_NAMES); + + titles = new String[]{"Queue Names"}; + bounds = new int[]{225}; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableColumn column = new TableColumn (_queuesTable, SWT.NONE); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + queuesTableSorter.setColumn(index); + final TableViewer viewer = _queuesTableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _queuesTableViewer.setContentProvider(new ContentProviderImpl(QUEUE_NAMES)); + _queuesTableViewer.setLabelProvider(new LabelProviderImpl(QUEUE_NAMES)); + _queuesTableViewer.setSorter(queuesTableSorter); + _queuesTable.setSortColumn(_queuesTable.getColumn(0)); + _queuesTable.setSortDirection(SWT.UP); + _queuesTableViewer.setInput(new String[]{"Select a binding key to view queues"}); + + //listener for double clicking to open the selection mbean + _queuesTable.addMouseListener(new MouseListener() + { + // MouseListener implementation + public void mouseDoubleClick(MouseEvent event) + { + openMBean(_queuesTable); + } + + public void mouseDown(MouseEvent e){} + public void mouseUp(MouseEvent e){} + }); + + _keysTableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + updateQueuesTable(); + } + }); + + //Side Buttons + Composite buttonsComposite = _toolkit.createComposite(bindingsGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + buttonsComposite.setLayoutData(gridData); + buttonsComposite.setLayout(new GridLayout()); + + final Button createBindingButton = _toolkit.createButton(buttonsComposite, "Create ...", SWT.PUSH); + createBindingButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + createNewBinding(createBindingButton.getShell()); + } + }); + + if(_ApiVersion.greaterThanOrEqualTo(1, 9) + && (isDirectExchange() ||isTopicExchange())) + { + final Button removeBindingButton = _toolkit.createButton(buttonsComposite, "Delete ...", SWT.PUSH); + removeBindingButton.setEnabled(false); + removeBindingButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + removeBinding(removeBindingButton.getShell()); + } + }); + + _queuesTableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _queuesTable.getSelectionIndex(); + + if (selectionIndex != -1) + { + removeBindingButton.setEnabled(true); + } + else + { + removeBindingButton.setEnabled(false); + } + } + }); + } + } + + private void updateQueuesTable() + { + int selectionIndex = _keysTable.getSelectionIndex(); + + if (selectionIndex != -1) + { + final CompositeData selectedMsg = (CompositeData)_keysTable.getItem(selectionIndex).getData(); + + String[] queues = (String[]) selectedMsg.get(QUEUE_NAMES); + _queuesTableViewer.setInput(queues); + } + else + { + _queuesTableViewer.setInput(new String[]{"Select a binding key to view queues"}); + } + } + + private boolean isFanoutExchange() + { + return _mbean.getProperty(EXCHANGE_TYPE).equalsIgnoreCase(FANOUT_EXCHANGE); + } + + private boolean isDirectExchange() + { + return _mbean.getProperty(EXCHANGE_TYPE).equalsIgnoreCase(DIRECT_EXCHANGE); + } + + private boolean isTopicExchange() + { + return _mbean.getProperty(EXCHANGE_TYPE).equalsIgnoreCase(TOPIC_EXCHANGE); + } + + /** + * Content Provider class for the table viewer + */ + private static class ContentProviderImpl implements IStructuredContentProvider + { + String type; + + public ContentProviderImpl(String type) + { + this.type = type; + } + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + public Object[] getElements(Object parent) + { + if(type.equals(BINDING_KEY)) + { + Collection<Object> rowCollection = ((TabularDataSupport) parent).values(); + + return rowCollection.toArray(); + } + else + { + //we have the list of queues, return directly + return (String[]) parent; + } + } + } + + /** + * Label Provider class for the routing key table viewer + */ + private static class LabelProviderImpl extends LabelProvider implements ITableLabelProvider + { + String type; + + public LabelProviderImpl(String type) + { + this.type = type; + } + + public String getColumnText(Object element, int columnIndex) + { + if(type.equals(BINDING_KEY)) //binding num and queue name table + { + switch (columnIndex) + { + case 0 : // key column + return String.valueOf(((CompositeDataSupport) element).get(BINDING_KEY)); + default : + return ""; + } + } + else //binding key-value pair table + { + switch (columnIndex) + { + case 0 : //queue name column + return String.valueOf(element); + default : + return ""; + } + } + } + + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + } + + /** + * Sorter class for the table viewer. + * + */ + public static class TableSorter extends ViewerSorter + { + private int column; + private static final int ASCENDING = 0; + private static final int DESCENDING = 1; + + private int direction = DESCENDING; + + private String type; + + public TableSorter(String type) + { + this.type = type; + this.column = 0; + direction = ASCENDING; + } + + public void setColumn(int column) + { + if (column == this.column) + { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } + else + { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + int comparison = 0; + + if(type.equals(BINDING_KEY))//binding num and queue name table + { + CompositeData binding1 = (CompositeData) e1; + CompositeData binding2 = (CompositeData) e2; + + switch(column) + { + case 0: + comparison = ((String) binding1.get(BINDING_KEY)).compareTo((String) binding2.get(BINDING_KEY)); + break; + default: + comparison = 0; + } + } + else //binding key-value pair table + { + switch(column) + { + case 0: + comparison = ((String)e1).compareTo((String) e2); + break; + default: + comparison = 0; + } + } + + + // If descending order, flip the direction + if(direction == DESCENDING) + { + comparison = -comparison; + } + return comparison; + } + } + + private void createNewBinding(Shell parent) + { + final Shell shell = ViewUtility.createModalDialogShell(parent, "Create New Binding"); + + Composite destinationComposite = _toolkit.createComposite(shell, SWT.NONE); + destinationComposite.setBackground(shell.getBackground()); + destinationComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + destinationComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(destinationComposite,"Queue:").setBackground(shell.getBackground()); + final Combo destinationCombo = new Combo(destinationComposite,SWT.NONE | SWT.READ_ONLY); + destinationCombo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Composite bindingComposite = _toolkit.createComposite(shell, SWT.NONE); + bindingComposite.setBackground(shell.getBackground()); + bindingComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + bindingComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(bindingComposite,"Binding:").setBackground(shell.getBackground()); + final Text bindingText = new Text(bindingComposite, SWT.BORDER); + bindingText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + if(isFanoutExchange()) + { + bindingText.setText("*"); + } + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + List<String> queueList = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_mbean.getVirtualHostName()); + + if(queueList.size() == 0) + { + destinationCombo.setItems(new String[]{"No queues available"}); + okButton.setEnabled(false); + } + else + { + Collections.sort(queueList); + destinationCombo.setItems(queueList.toArray(new String[0])); + } + destinationCombo.select(0); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String binding = bindingText.getText(); + + if (!isFanoutExchange() && (binding == null || binding.length() == 0)) + { + ViewUtility.popupErrorMessage("Create New Binding", "Please enter a valid binding"); + return; + } + + String destQueue = destinationCombo.getItem(destinationCombo.getSelectionIndex()).toString(); + + shell.dispose(); + + try + { + _emb.createNewBinding(destQueue, binding); + ViewUtility.operationResultFeedback(null, "Created new Binding", null); + } + catch (Exception e4) + { + ViewUtility.operationFailedStatusBarMessage("Error creating new Binding"); + MBeanUtility.handleException(_mbean, e4); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private void removeBinding(Shell parent) + { + int selectionIndex = _keysTable.getSelectionIndex(); + if (selectionIndex == -1) + { + return; + } + + final CompositeData selectedBindingRecord = (CompositeData)_keysTable.getItem(selectionIndex).getData(); + + final String bindingKey = (String) selectedBindingRecord.get(BINDING_KEY); + + selectionIndex = _queuesTable.getSelectionIndex(); + if (selectionIndex == -1) + { + return; + } + + final String queueName = (String)_queuesTable.getItem(selectionIndex).getData(); + + + int response = ViewUtility.popupOkCancelConfirmationMessage("Delete Binding", + "Delete the following binding?\n\n" + + "Binding Key: " + bindingKey + "\n" + + "Queue: " + queueName + "\n" + + "Exchange: " + _mbean.getName()); + + if (response == SWT.OK) + { + try + { + _emb.removeBinding(queueName, bindingKey); + ViewUtility.operationResultFeedback(null, "Removed Binding", null); + } + catch (Exception e) + { + ViewUtility.operationFailedStatusBarMessage("Error removing Binding"); + MBeanUtility.handleException(_mbean, e); + } + + refresh(_mbean); + } + } + + private void openMBean(Table table) + { + int selectionIndex = table.getSelectionIndex(); + + if (selectionIndex == -1) + { + return; + } + + String queueName = (String) table.getItem(selectionIndex).getData(); + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean); + ManagedBean selectedMBean = serverRegistry.getQueue(queueName, _mbean.getVirtualHostName()); + + if(selectedMBean == null) + { + ViewUtility.popupErrorMessage("Error", "Unable to retrieve the selected MBean to open it"); + return; + } + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID); + try + { + view.openMBean(selectedMBean); + } + catch (Exception ex) + { + MBeanUtility.handleException(selectedMBean, ex); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/HeadersExchangeOperationsTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/HeadersExchangeOperationsTabControl.java new file mode 100644 index 0000000000..e22898fb93 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/exchange/HeadersExchangeOperationsTabControl.java @@ -0,0 +1,711 @@ +/* + * + * 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.exchange; + +import static org.apache.qpid.management.common.mbeans.ManagedExchange.HDR_BINDING_NUMBER; +import static org.apache.qpid.management.common.mbeans.ManagedExchange.HDR_QUEUE_BINDINGS; +import static org.apache.qpid.management.common.mbeans.ManagedExchange.HDR_QUEUE_NAME; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.TabularDataSupport; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.ServerRegistry; +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.MBeanView; +import org.apache.qpid.management.ui.views.TabControl; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; + + +/** + * Control class for the Headers Exchange mbean Operations tab. + */ +public class HeadersExchangeOperationsTabControl extends TabControl +{ + private FormToolkit _toolkit; + private ScrolledForm _form; + private Table _bindingNumberTable = null; + private TableViewer _bindingNumberTableViewer = null; + private Table _headersTable = null; + private TableViewer _headersTableViewer = null; + private Composite _paramsComposite = null; + + private TabularDataSupport _bindings = null; + private ManagedExchange _emb; + + public HeadersExchangeOperationsTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc) + { + super(tabFolder); + _mbean = mbean; + _emb = (ManagedExchange) MBeanServerInvocationHandler.newProxyInstance(mbsc, + mbean.getObjectName(), ManagedExchange.class, false); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createScrolledForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + createComposites(); + createWidgets(); + } + + private void createComposites() + { + _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + _paramsComposite.setLayout(new GridLayout()); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + _bindingNumberTable.setFocus(); + } + + @Override + public void refresh(ManagedBean mbean) + { + + _bindings = null; + try + { + //gather a list of all keys and queues for display and selection + _bindings = (TabularDataSupport) _emb.bindings(); + } + catch (Exception e) + { + MBeanUtility.handleException(_mbean,e); + } + + _bindingNumberTableViewer.setInput(_bindings); + + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + private void createWidgets() + { + Group bindingsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE); + bindingsGroup.setBackground(_paramsComposite.getBackground()); + bindingsGroup.setText("Bindings"); + bindingsGroup.setLayout(new GridLayout(2,false)); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + bindingsGroup.setLayoutData(gridData); + + Composite tablesComposite = _toolkit.createComposite(bindingsGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.minimumHeight = 250; + gridData.heightHint = 250; + tablesComposite.setLayoutData(gridData); + tablesComposite.setLayout(new GridLayout(2,false)); + + //table of bindings for the exchange + _bindingNumberTable = new Table (tablesComposite, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _bindingNumberTable.setLinesVisible(true); + _bindingNumberTable.setHeaderVisible(true); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + data.minimumHeight = 300; + data.heightHint = 300; + _bindingNumberTable.setLayoutData(data); + + _bindingNumberTableViewer = new TableViewer(_bindingNumberTable); + final TableSorter tableSorter = new TableSorter(HDR_BINDING_NUMBER); + + String[] titles = {"Binding Number", "Queue Name"}; + int[] bounds = {135, 175}; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableColumn column = new TableColumn (_bindingNumberTable, SWT.NONE); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _bindingNumberTableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _bindingNumberTableViewer.setContentProvider(new ContentProviderImpl(HDR_BINDING_NUMBER)); + _bindingNumberTableViewer.setLabelProvider(new LabelProviderImpl(HDR_BINDING_NUMBER)); + _bindingNumberTableViewer.setSorter(tableSorter); + _bindingNumberTable.setSortColumn(_bindingNumberTable.getColumn(0)); + _bindingNumberTable.setSortDirection(SWT.UP); + + //table of header bindings + _headersTable = new Table (tablesComposite, SWT.SINGLE | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _headersTable.setLinesVisible (true); + _headersTable.setHeaderVisible (true); + data = new GridData(SWT.FILL, SWT.FILL, true, true); + data.minimumHeight = 300; + data.heightHint = 300; + _headersTable.setLayoutData(data); + + _headersTableViewer = new TableViewer(_headersTable); + final TableSorter queuesTableSorter = new TableSorter(HDR_QUEUE_BINDINGS); + + titles = new String[]{"Header Bindings"}; + bounds = new int[]{225}; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableColumn column = new TableColumn (_headersTable, SWT.NONE); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + queuesTableSorter.setColumn(index); + final TableViewer viewer = _headersTableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _headersTableViewer.setContentProvider(new ContentProviderImpl(HDR_QUEUE_BINDINGS)); + _headersTableViewer.setLabelProvider(new LabelProviderImpl(HDR_QUEUE_BINDINGS)); + _headersTableViewer.setSorter(queuesTableSorter); + _headersTable.setSortColumn(_headersTable.getColumn(0)); + _headersTable.setSortDirection(SWT.UP); + _headersTableViewer.setInput(new String[]{"Select a binding to view key-value pairs"}); + + _bindingNumberTableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _bindingNumberTable.getSelectionIndex(); + + if (selectionIndex != -1) + { + final CompositeData selectedMsg = (CompositeData)_bindingNumberTable.getItem(selectionIndex).getData(); + + String[] bindings = (String[]) selectedMsg.get(HDR_QUEUE_BINDINGS); + _headersTableViewer.setInput(bindings); + } + else + { + _headersTableViewer.setInput(new String[]{"Select a binding to view key-value pairs"}); + } + } + }); + + //listener for double clicking to open the selection mbean + _bindingNumberTable.addMouseListener(new MouseListener() + { + // MouseListener implementation + public void mouseDoubleClick(MouseEvent event) + { + openMBean(_bindingNumberTable); + } + + public void mouseDown(MouseEvent e){} + public void mouseUp(MouseEvent e){} + }); + + //Side Buttons + Composite buttonsComposite = _toolkit.createComposite(bindingsGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + buttonsComposite.setLayoutData(gridData); + buttonsComposite.setLayout(new GridLayout()); + + final Button createBindingButton = _toolkit.createButton(buttonsComposite, "Create ...", SWT.PUSH); + createBindingButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + createNewBinding(createBindingButton.getShell()); + } + }); + + } + + + /** + * Content Provider class for the table viewer + */ + private static class ContentProviderImpl implements IStructuredContentProvider + { + String type; + + public ContentProviderImpl(String type) + { + this.type = type; + } + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + public Object[] getElements(Object parent) + { + if(type.equals(HDR_BINDING_NUMBER)) + { + Collection<Object> rowCollection = ((TabularDataSupport) parent).values(); + + return rowCollection.toArray(); + } + else + { + //we have the list of bindings, return directly + return (String[]) parent; + } + } + } + + /** + * Label Provider class for the routing key table viewer + */ + private static class LabelProviderImpl extends LabelProvider implements ITableLabelProvider + { + String type; + + public LabelProviderImpl(String type) + { + this.type = type; + } + + public String getColumnText(Object element, int columnIndex) + { + if(type.equals(HDR_BINDING_NUMBER)) //binding num and queue name table + { + switch (columnIndex) + { + case 0 : // binding number column + return String.valueOf(((CompositeDataSupport) element).get(HDR_BINDING_NUMBER)); + case 1 : // queue name column + return (String) ((CompositeDataSupport) element).get(HDR_QUEUE_NAME); + default : + return ""; + } + } + else //binding key-value pair table + { + switch (columnIndex) + { + case 0 : //header binding column + return String.valueOf(element); + default : + return ""; + } + } + } + + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + } + + /** + * Sorter class for the table viewer. + * + */ + public static class TableSorter extends ViewerSorter + { + private int column; + private static final int ASCENDING = 0; + private static final int DESCENDING = 1; + + private int direction = DESCENDING; + + private String type; + + public TableSorter(String type) + { + this.type = type; + this.column = 0; + direction = ASCENDING; + } + + public void setColumn(int column) + { + if (column == this.column) + { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } + else + { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + int comparison = 0; + + if(type.equals(HDR_BINDING_NUMBER)) //binding num and queue name table + { + CompositeData binding1 = (CompositeData) e1; + CompositeData binding2 = (CompositeData) e2; + + switch(column) + { + case 0: // binding number column + comparison = ((Integer) binding1.get(HDR_BINDING_NUMBER)).compareTo((Integer) binding2.get(HDR_BINDING_NUMBER)); + break; + case 1: // queue name column + comparison = ((String) binding1.get(HDR_QUEUE_NAME)).compareTo((String) binding2.get(HDR_QUEUE_NAME)); + break; + default: + comparison = 0; + } + } + else //binding key-value pair table + { + switch(column) + { + case 0: //header binding column + comparison = ((String)e1).compareTo((String) e2); + break; + default: + comparison = 0; + } + } + + // If descending order, flip the direction + if(direction == DESCENDING) + { + comparison = -comparison; + } + return comparison; + } + } + + private void createNewBinding(Shell parent) + { + final Shell shell = ViewUtility.createModalDialogShell(parent, "Create New Binding"); + + Composite queueNameComposite = _toolkit.createComposite(shell, SWT.NONE); + queueNameComposite.setBackground(shell.getBackground()); + GridData layoutData = new GridData(SWT.CENTER, SWT.TOP, true, false); + layoutData.minimumWidth = 300; + queueNameComposite.setLayoutData(layoutData); + queueNameComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(queueNameComposite,"Queue:").setBackground(shell.getBackground()); + final Combo destinationCombo = new Combo(queueNameComposite,SWT.NONE | SWT.READ_ONLY); + destinationCombo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + final ScrolledComposite scrolledComposite = new ScrolledComposite(shell, SWT.V_SCROLL); + scrolledComposite.setExpandHorizontal(true); + scrolledComposite.setLayout(new GridLayout()); + scrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + scrolledComposite.setBackground(shell.getBackground()); + + final Composite bindingComposite = _toolkit.createComposite(scrolledComposite, SWT.NONE); + bindingComposite.setBackground(scrolledComposite.getBackground()); + bindingComposite.setLayout(new GridLayout(2,true)); + layoutData = new GridData(SWT.FILL, SWT.TOP, true, false); + bindingComposite.setLayoutData(layoutData); + scrolledComposite.setContent(bindingComposite); + + Composite addMoreButtonComp = _toolkit.createComposite(shell); + addMoreButtonComp.setBackground(shell.getBackground()); + addMoreButtonComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + addMoreButtonComp.setLayout(new GridLayout()); + + final Button addMoreButton = _toolkit.createButton(addMoreButtonComp, "Add additional field", SWT.PUSH); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + List<String> queueList = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_mbean.getVirtualHostName()); + + if(queueList.size() == 0) + { + destinationCombo.setItems(new String[]{"No queues available"}); + okButton.setEnabled(false); + } + else + { + Collections.sort(queueList); + destinationCombo.setItems(queueList.toArray(new String[0])); + } + destinationCombo.select(0); + + final HashMap<Text, Text> headerBindingHashMap = new HashMap<Text, Text>(); + + //add headings + Label keyLabel = _toolkit.createLabel(bindingComposite,"Key:"); + keyLabel.setBackground(bindingComposite.getBackground()); + keyLabel.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false)); + + Label valueLabel = _toolkit.createLabel(bindingComposite,"Value:"); + valueLabel.setBackground(bindingComposite.getBackground()); + valueLabel.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, false)); + + //add the x-match key by default and offer a comobo to select its value + final Text xmatchKeyText = new Text(bindingComposite, SWT.BORDER); + xmatchKeyText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + xmatchKeyText.setText("x-match"); + xmatchKeyText.setEditable(false); + + final Combo xmatchValueCombo = new Combo(bindingComposite,SWT.NONE | SWT.READ_ONLY); + xmatchValueCombo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + xmatchValueCombo.setItems(new String[]{"any", "all"}); + xmatchValueCombo.select(0); + + //make some empty key-value fields + for(int i=0; i < 4; i++) + { + Text keyText = new Text(bindingComposite, SWT.BORDER); + Text valueText = new Text(bindingComposite, SWT.BORDER); + keyText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + valueText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + headerBindingHashMap.put(keyText, valueText); + } + bindingComposite.setSize(bindingComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + + //allow adding more fields for additional key-value pairs + addMoreButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + Text keyText = new Text(bindingComposite, SWT.BORDER); + Text valueText = new Text(bindingComposite, SWT.BORDER); + keyText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + valueText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + headerBindingHashMap.put(keyText, valueText); + + bindingComposite.setSize(bindingComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + bindingComposite.layout(true); + scrolledComposite.layout(true); + } + }); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String xMatchString = xmatchValueCombo.getText(); + + String destQueue = destinationCombo.getItem(destinationCombo.getSelectionIndex()).toString(); + + StringBuffer bindingValue = new StringBuffer(); + + //insert the x-match key-value pair + if (xMatchString.equalsIgnoreCase("any")) + { + bindingValue.append("x-match=any"); + } + else + { + bindingValue.append("x-match=all"); + } + + //insert the other key-value pairs + for (Text keyText : headerBindingHashMap.keySet()) + { + + String key = keyText.getText(); + if(key == null || key.length() == 0) + { + continue; + } + + Text valueText = headerBindingHashMap.get(keyText); + String value = valueText.getText(); + + bindingValue.append(","); + bindingValue.append(key + "="); + //empty values are permitted, signalling only key-presence is required + if(value != null && value.length() > 0) + { + bindingValue.append(value); + } + } + + shell.dispose(); + + try + { + _emb.createNewBinding(destQueue, bindingValue.toString()); + ViewUtility.operationResultFeedback(null, "Created new Binding", null); + } + catch (Exception e4) + { + ViewUtility.operationFailedStatusBarMessage("Error creating new Binding"); + MBeanUtility.handleException(_mbean, e4); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private void openMBean(Table table) + { + int selectionIndex = table.getSelectionIndex(); + + if (selectionIndex == -1) + { + return; + } + + CompositeData bindingResult = (CompositeData) table.getItem(selectionIndex).getData(); + String queueName = (String) bindingResult.get(HDR_QUEUE_NAME); + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean); + ManagedBean selectedMBean = serverRegistry.getQueue(queueName, _mbean.getVirtualHostName()); + + if(selectedMBean == null) + { + ViewUtility.popupErrorMessage("Error", "Unable to retrieve the selected MBean to open it"); + return; + } + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID); + try + { + view.openMBean(selectedMBean); + } + catch (Exception ex) + { + MBeanUtility.handleException(selectedMBean, ex); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java new file mode 100644 index 0000000000..1ae48f5c6c --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/ConfigurationFileTabControl.java @@ -0,0 +1,591 @@ +/* + * + * 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.logging; + +import static org.apache.qpid.management.common.mbeans.LoggingManagement.LOGGER_LEVEL; +import static org.apache.qpid.management.common.mbeans.LoggingManagement.LOGGER_NAME; + +import java.util.ArrayList; +import java.util.HashMap; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularDataSupport; + +import static org.apache.qpid.management.ui.Constants.FONT_BOLD; + +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.common.mbeans.LoggingManagement; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.TabControl; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; + + +/** + * Control class for the LoggingManagement mbean ConfigFile Options tab. + */ +public class ConfigurationFileTabControl extends TabControl +{ + private FormToolkit _toolkit; + private ScrolledForm _form; + private Table _table = null; + private TableViewer _tableViewer = null; + private Composite _headerComposite = null; + private Composite _paramsComposite = null; + + private Label _configFileRootLoggerLevelLabel = null; + private Label _logWatchIntervalLabel = null; + private String[] _availableLoggerLevels; + private TabularDataSupport _configFileLoggerLevels = null; + private LoggingManagement _lmmb; + private ApiVersion _ApiVersion; + + public ConfigurationFileTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc) + { + super(tabFolder); + _mbean = mbean; + _lmmb = (LoggingManagement) + MBeanServerInvocationHandler.newProxyInstance(mbsc, mbean.getObjectName(), + LoggingManagement.class, false); + _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion(); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createScrolledForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + createComposites(); + createWidgets(); + } + + private void createComposites() + { + + _headerComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _headerComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + _headerComposite.setLayout(new GridLayout()); + + _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + _paramsComposite.setLayout(new GridLayout()); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + _table.setFocus(); + } + + @Override + public void refresh(ManagedBean mbean) + { + String configFileRootLoggerLevel = "-"; + try + { + configFileRootLoggerLevel = _lmmb.getConfigFileRootLoggerLevel(); + } + catch (Exception e1) + { + MBeanUtility.handleException(_mbean, e1); + } + + int log4jLogWatchInterval = -1; + try + { + log4jLogWatchInterval = _lmmb.getLog4jLogWatchInterval(); + } + catch (Exception e2) + { + MBeanUtility.handleException(_mbean, e2); + } + + _configFileLoggerLevels = null; + try + { + _configFileLoggerLevels = (TabularDataSupport) _lmmb.viewConfigFileLoggerLevels(); + } + catch (Exception e3) + { + MBeanUtility.handleException(_mbean, e3); + } + + _configFileRootLoggerLevelLabel.setText(String.valueOf(configFileRootLoggerLevel)); + if (log4jLogWatchInterval == 0) + { + _logWatchIntervalLabel.setText("Disabled (0 sec)"); + } + else + { + _logWatchIntervalLabel.setText(String.valueOf(log4jLogWatchInterval) + " seconds"); + } + _tableViewer.setInput(_configFileLoggerLevels); + + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + private void createWidgets() + { + try + { + _availableLoggerLevels = _lmmb.getAvailableLoggerLevels(); + } + catch(Exception e) + { + _availableLoggerLevels = new String[]{"ALL","TRACE","DEBUG","INFO","WARN","ERROR","FATAL","OFF"}; + } + + Label noteLabel = _toolkit.createLabel(_headerComposite, + "NOTE: These options modify the configuration file. " + + "Changes only take effect automatically if LogWatch is enabled."); + Label noteLabel2 = _toolkit.createLabel(_headerComposite, + "A child Logger set to a non-inherited Level in the Runtime tab " + + "will retain that value after the file is reloaded."); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + noteLabel.setLayoutData(gridData); + gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + noteLabel2.setLayoutData(gridData); + + Group configFileLoggerLevelsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE); + configFileLoggerLevelsGroup.setBackground(_paramsComposite.getBackground()); + configFileLoggerLevelsGroup.setText("Configuration File Logger Levels"); + configFileLoggerLevelsGroup.setLayout(new GridLayout()); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + configFileLoggerLevelsGroup.setLayoutData(gridData); + + Composite tableComposite = _toolkit.createComposite(configFileLoggerLevelsGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.heightHint = 250; + gridData.minimumHeight = 250; + tableComposite.setLayoutData(gridData); + GridLayout gridLayout = new GridLayout(); + + tableComposite.setLayout(gridLayout); + + _table = new Table (tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _table.setLinesVisible (true); + _table.setHeaderVisible (true); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + _table.setLayoutData(data); + + _tableViewer = new TableViewer(_table); + final LoggingTableSorter tableSorter = new LoggingTableSorter(); + + String[] titles = { LOGGER_NAME, LOGGER_LEVEL }; + int[] bounds = { 600, 75 }; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE); + final TableColumn column = viewerColumn.getColumn(); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _tableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _tableViewer.setContentProvider(new LoggingTableContentProvider()); + _tableViewer.setLabelProvider(new LoggingTableLabelProvider()); + _tableViewer.setSorter(tableSorter); + _table.setSortColumn(_table.getColumn(0)); + _table.setSortDirection(SWT.UP); + _table.addMouseListener(new MouseListener() + { + public void mouseDoubleClick(MouseEvent event) + { + editLoggerLevel(_table.getShell()); + } + + public void mouseDown(MouseEvent e){} + public void mouseUp(MouseEvent e){} + }); + + final Button logLevelEditButton = _toolkit.createButton(configFileLoggerLevelsGroup, "Edit Selected Logger(s)...", SWT.PUSH); + logLevelEditButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + logLevelEditButton.setEnabled(false); + logLevelEditButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + editLoggerLevel(logLevelEditButton.getShell()); + } + }); + + _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _table.getSelectionIndex(); + + if(selectionIndex != -1) + { + logLevelEditButton.setEnabled(true); + } + else + { + logLevelEditButton.setEnabled(false); + } + } + }); + + + Composite attributesComposite = _toolkit.createComposite(_paramsComposite); + gridData = new GridData(SWT.LEFT, SWT.FILL, false, true); + attributesComposite.setLayoutData(gridData); + gridLayout = new GridLayout(3,false); + attributesComposite.setLayout(gridLayout); + + Group configFileRootLoggerLevelGroup = new Group(attributesComposite, SWT.SHADOW_NONE); + configFileRootLoggerLevelGroup.setBackground(attributesComposite.getBackground()); + configFileRootLoggerLevelGroup.setText("Config File RootLogger Level"); + gridData = new GridData(SWT.LEFT, SWT.TOP, true, false); + configFileRootLoggerLevelGroup.setLayoutData(gridData); + configFileRootLoggerLevelGroup.setLayout(new GridLayout(2,false)); + + _configFileRootLoggerLevelLabel = _toolkit.createLabel(configFileRootLoggerLevelGroup, "-"); + _configFileRootLoggerLevelLabel.setFont(ApplicationRegistry.getFont(FONT_BOLD)); + _configFileRootLoggerLevelLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); + + final Button configFileRootLoggerLevelButton = _toolkit.createButton(configFileRootLoggerLevelGroup, "Edit ...", SWT.PUSH); + configFileRootLoggerLevelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false)); + configFileRootLoggerLevelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + editRootLoggerLevel(configFileRootLoggerLevelButton.getShell()); + } + }); + + + Group logWatchIntervalGroup = new Group(attributesComposite, SWT.SHADOW_NONE); + logWatchIntervalGroup.setBackground(attributesComposite.getBackground()); + logWatchIntervalGroup.setText("LogWatch Interval"); + gridData = new GridData(SWT.LEFT, SWT.FILL, true, false); + logWatchIntervalGroup.setLayoutData(gridData); + logWatchIntervalGroup.setLayout(new GridLayout()); + + _logWatchIntervalLabel = _toolkit.createLabel(logWatchIntervalGroup, "-"); + _logWatchIntervalLabel.setFont(ApplicationRegistry.getFont(FONT_BOLD)); + _logWatchIntervalLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, true)); + + if(_ApiVersion.greaterThanOrEqualTo(1, 4)) + { + Group reloadConfigFileGroup = new Group(attributesComposite, SWT.SHADOW_NONE); + reloadConfigFileGroup.setBackground(attributesComposite.getBackground()); + reloadConfigFileGroup.setText("Reload Configuration File"); + gridData = new GridData(SWT.LEFT, SWT.TOP, true, false); + reloadConfigFileGroup.setLayoutData(gridData); + reloadConfigFileGroup.setLayout(new GridLayout()); + + final Button reloadConfigFileButton = _toolkit.createButton(reloadConfigFileGroup, "Reload Config File", SWT.PUSH); + reloadConfigFileButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false)); + reloadConfigFileButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int response = ViewUtility.popupOkCancelConfirmationMessage("Reload", + "Reload Logging Configuration File?"); + if (response == SWT.OK) + { + try + { + _lmmb.reloadConfigFile(); + ViewUtility.operationResultFeedback(null, "Reloaded Logging Configuration File", null); + + } + catch (Exception ex) + { + ViewUtility.operationFailedStatusBarMessage("Error Reloading Logging Configuration File"); + MBeanUtility.handleException(_mbean, ex); + } + + refresh(_mbean);; + } + } + }); + } + } + + + + private void editLoggerLevel(Shell parent) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + int[] selectedIndices = _table.getSelectionIndices(); + + final ArrayList<String> selectedLoggers = new ArrayList<String>(); + + for(int index = 0; index < selectedIndices.length ; index++) + { + CompositeData selectedLogger = (CompositeData)_table.getItem(selectedIndices[index]).getData(); + String user = (String) selectedLogger.get(LOGGER_NAME); + selectedLoggers.add(user); + } + + final Shell shell = ViewUtility.createModalDialogShell(parent, "Set Config File Logger Level(s)"); + + _toolkit.createLabel(shell, "Logger(s): ").setBackground(shell.getBackground()); + + final Text headerText = new Text(shell, SWT.WRAP | SWT.V_SCROLL | SWT.BORDER ); + headerText.setEditable(false); + GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); + data.minimumHeight = 125; + data.heightHint = 125; + data.minimumWidth = 575; + data.widthHint = 575; + headerText.setLayoutData(data); + + String lineSeperator = System.getProperty("line.separator"); + for(String loggerName : selectedLoggers) + { + headerText.append(loggerName + lineSeperator); + } + headerText.setSelection(0); + + Composite levelComp = _toolkit.createComposite(shell); + levelComp.setBackground(shell.getBackground()); + levelComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + levelComp.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(levelComp,"Level: ").setBackground(levelComp.getBackground()); + final Combo levelCombo = new Combo (levelComp, SWT.READ_ONLY ); + levelCombo.setItems(_availableLoggerLevels); + levelCombo.select(0); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String level = levelCombo.getItem(levelCombo.getSelectionIndex()).toString(); + + shell.close(); + + try + { + HashMap<String,Boolean> results = new HashMap<String,Boolean>(); + + //perform the updates, save the results. + for(String logger : selectedLoggers) + { + boolean result = _lmmb.setConfigFileLoggerLevel(logger, level); + results.put(logger, result); + } + + //categorise the overall result + boolean overallResult = true; + for(boolean result : results.values()) + { + if (!result) + { + overallResult = false; + } + } + + //output the result to status bar if all succeed, and dialogue if not + if(overallResult) + { + ViewUtility.operationResultFeedback(overallResult, "Updated ConfigFile Logger Level(s)", null); + } + else + { + String failedToSetLevelOfLoggers = ""; + for(String logger : results.keySet()) + { + if(!results.get(logger)) + { + failedToSetLevelOfLoggers = failedToSetLevelOfLoggers.concat(logger + ", "); + } + } + + //cut off last ", " + int lastIndex = failedToSetLevelOfLoggers.lastIndexOf(','); + if (lastIndex != -1) + { + failedToSetLevelOfLoggers = failedToSetLevelOfLoggers.substring(0, lastIndex); + } + + ViewUtility.operationResultFeedback(overallResult, null, + "Failed to update ConfigFile Logger Level(s): " + + failedToSetLevelOfLoggers); + } + } + catch(Exception e4) + { + ViewUtility.operationFailedStatusBarMessage("Error updating Config File Logger Level(s)"); + MBeanUtility.handleException(_mbean, e4); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + } + + private void editRootLoggerLevel(Shell parent) + { + final Shell shell = ViewUtility.createModalDialogShell(parent, "ConfigFile RootLogger Level"); + + Composite levelComp = _toolkit.createComposite(shell); + levelComp.setBackground(shell.getBackground()); + levelComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + levelComp.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(levelComp,"RootLogger level: ").setBackground(levelComp.getBackground()); + final Combo levelCombo = new Combo (levelComp, SWT.READ_ONLY ); + levelCombo.setItems(_availableLoggerLevels); + levelCombo.select(0); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String selection = levelCombo.getItem(levelCombo.getSelectionIndex()).toString(); + shell.dispose(); + try + { + boolean result = _lmmb.setConfigFileRootLoggerLevel(selection); + ViewUtility.operationResultFeedback(result, + "Updated ConfigFile RootLogger Level", "Failed to update ConfigFile RootLogger Level"); + } + catch (Exception e5) + { + ViewUtility.operationFailedStatusBarMessage("Error updating ConfigFile RootLogger Level"); + MBeanUtility.handleException(_mbean, e5); + } + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableContentProvider.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableContentProvider.java new file mode 100644 index 0000000000..6ef3ab70a7 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableContentProvider.java @@ -0,0 +1,52 @@ +/* + * + * 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.logging; + +import java.util.Collection; + +import javax.management.openmbean.TabularDataSupport; + +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.Viewer; + +/** + * Content Provider class for theLogging Management table viewers + */ +public class LoggingTableContentProvider implements IStructuredContentProvider +{ + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + public Object[] getElements(Object parent) + { + Collection<Object> rowCollection = ((TabularDataSupport) parent).values(); + + return rowCollection.toArray(); + } +}
\ No newline at end of file diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableLabelProvider.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableLabelProvider.java new file mode 100644 index 0000000000..3156e3f1c4 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableLabelProvider.java @@ -0,0 +1,59 @@ +/* + * + * 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.logging; + +import static org.apache.qpid.management.common.mbeans.LoggingManagement.LOGGER_LEVEL; +import static org.apache.qpid.management.common.mbeans.LoggingManagement.LOGGER_NAME; + + +import javax.management.openmbean.CompositeDataSupport; + +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.graphics.Image; + +/** + * Label Provider class for the LoggingManagement table viewers + */ +public class LoggingTableLabelProvider extends LabelProvider implements ITableLabelProvider +{ + @Override + public String getColumnText(Object element, int columnIndex) + { + switch (columnIndex) + { + case 0 : // logger name column + return (String) ((CompositeDataSupport) element).get(LOGGER_NAME); + case 1 : // logger level column + return (String) ((CompositeDataSupport) element).get(LOGGER_LEVEL); + default : + return "-"; + } + } + + @Override + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableSorter.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableSorter.java new file mode 100644 index 0000000000..99d22f2cb8 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/LoggingTableSorter.java @@ -0,0 +1,90 @@ +/* + * + * 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.logging; + +import static org.apache.qpid.management.common.mbeans.LoggingManagement.LOGGER_LEVEL; +import static org.apache.qpid.management.common.mbeans.LoggingManagement.LOGGER_NAME; + +import javax.management.openmbean.CompositeData; + +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; + +/** + * Sorter class for the Logging Management table viewers. + */ +public class LoggingTableSorter extends ViewerSorter +{ + private static final int ASCENDING = 0; + private static final int DESCENDING = 1; + + private int column; + private int direction; + + public LoggingTableSorter() + { + this.column = 0; + direction = ASCENDING; + } + + public void setColumn(int column) + { + if (column == this.column) + { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } + else + { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + CompositeData logger1 = (CompositeData) e1; + CompositeData logger2 = (CompositeData) e2; + + int comparison = 0; + switch(column) + { + case 0: + comparison = String.valueOf(logger1.get(LOGGER_NAME)).compareTo( + String.valueOf(logger2.get(LOGGER_NAME))); + break; + case 1: + comparison = String.valueOf(logger1.get(LOGGER_LEVEL)).compareTo( + String.valueOf(logger2.get(LOGGER_LEVEL))); + break; + default: + comparison = 0; + } + // If descending order, flip the direction + if (direction == DESCENDING) + { + comparison = -comparison; + } + return comparison; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/RuntimeTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/RuntimeTabControl.java new file mode 100644 index 0000000000..1ae97cfcb6 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/logging/RuntimeTabControl.java @@ -0,0 +1,595 @@ +/* + * + * 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.logging; + +import static org.apache.qpid.management.common.mbeans.LoggingManagement.LOGGER_LEVEL; +import static org.apache.qpid.management.common.mbeans.LoggingManagement.LOGGER_NAME; + +import java.util.ArrayList; +import java.util.HashMap; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.TabularDataSupport; + +import static org.apache.qpid.management.ui.Constants.FONT_BOLD; + +import org.apache.qpid.management.common.mbeans.LoggingManagement; +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.TabControl; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.viewers.IColorProvider; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; + + +/** + * Control class for the LoggingManagement mbean Runtime Options tab. + */ +public class RuntimeTabControl extends TabControl +{ + private FormToolkit _toolkit; + private ScrolledForm _form; + private Table _table = null; + private TableViewer _tableViewer = null; + private Composite _headerComposite = null; + private Composite _paramsComposite = null; + + private Label _runtimeRootLoggerLevelLabel = null; + private String[] _availableLoggerLevels; + private TabularDataSupport _runtimeLoggerLevels = null; + private ArrayList<String> _configFileLoggerNames = new ArrayList<String>(); + private LoggingManagement _lmmb; + + public RuntimeTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc) + { + super(tabFolder); + _mbean = mbean; + _lmmb = (LoggingManagement) + MBeanServerInvocationHandler.newProxyInstance(mbsc, mbean.getObjectName(), + LoggingManagement.class, false); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createScrolledForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + createComposites(); + createWidgets(); + } + + private void createComposites() + { + + _headerComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _headerComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + _headerComposite.setLayout(new GridLayout()); + + _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + _paramsComposite.setLayout(new GridLayout()); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + _table.setFocus(); + } + + @Override + public void refresh(ManagedBean mbean) + { + String runtimeRootLoggerLevel = "-"; + try + { + runtimeRootLoggerLevel = _lmmb.getRuntimeRootLoggerLevel(); + } + catch(Exception e1) + { + MBeanUtility.handleException(_mbean, e1); + } + + _runtimeLoggerLevels = null; + try + { + _runtimeLoggerLevels = (TabularDataSupport) _lmmb.viewEffectiveRuntimeLoggerLevels(); + } + catch(Exception e2) + { + MBeanUtility.handleException(_mbean, e2); + } + + + try + { + TabularDataSupport confLoggers = (TabularDataSupport) _lmmb.viewConfigFileLoggerLevels(); + ArrayList<String> confLoggerNames = new ArrayList<String>(); + + for(Object obj : confLoggers.values()) + { + CompositeData comp = (CompositeData) obj; + confLoggerNames.add((String) comp.get(LOGGER_NAME)); + } + + _configFileLoggerNames = confLoggerNames; + } + catch(Exception e2) + { + //dont signal the failure, just dont highlight the config file loggers, empty the existing list. + _configFileLoggerNames.clear(); + } + + _runtimeRootLoggerLevelLabel.setText(String.valueOf(runtimeRootLoggerLevel)); + _tableViewer.setInput(_runtimeLoggerLevels); + + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + private void createWidgets() + { + try + { + _availableLoggerLevels = _lmmb.getAvailableLoggerLevels(); + } + catch(Exception e) + { + _availableLoggerLevels = new String[]{"ALL","TRACE","DEBUG","INFO","WARN","ERROR","FATAL","OFF"}; + } + + Label noteLabel = _toolkit.createLabel(_headerComposite, + "NOTE: These options modify only the live runtime settings. " + + "Non-default values will be lost following broker restart."); + Label noteLabel2 = _toolkit.createLabel(_headerComposite, + "Loggers currently defined in the configuration file are " + + "highlighted. The other Loggers inherit a Level by default."); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + noteLabel.setLayoutData(gridData); + gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + noteLabel2.setLayoutData(gridData); + + Group effectiveRuntimeLoggerLevelsGroup = new Group(_paramsComposite, SWT.SHADOW_NONE); + effectiveRuntimeLoggerLevelsGroup.setBackground(_paramsComposite.getBackground()); + effectiveRuntimeLoggerLevelsGroup.setText("Effective Runtime Logger Levels"); + effectiveRuntimeLoggerLevelsGroup.setLayout(new GridLayout()); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + effectiveRuntimeLoggerLevelsGroup.setLayoutData(gridData); + + Composite tableComposite = _toolkit.createComposite(effectiveRuntimeLoggerLevelsGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.heightHint = 250; + gridData.minimumHeight = 250; + tableComposite.setLayoutData(gridData); + GridLayout gridLayout = new GridLayout(); + tableComposite.setLayout(gridLayout); + + _table = new Table (tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _table.setLinesVisible (true); + _table.setHeaderVisible (true); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + _table.setLayoutData(data); + + _tableViewer = new TableViewer(_table); + final LoggingTableSorter tableSorter = new LoggingTableSorter(); + + String[] titles = { LOGGER_NAME, LOGGER_LEVEL }; + int[] bounds = { 600, 75 }; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE); + final TableColumn column = viewerColumn.getColumn(); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _tableViewer; + int dir = viewer.getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = (dir == SWT.UP ? SWT.DOWN : SWT.UP); + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _tableViewer.setContentProvider(new LoggingTableContentProvider()); + _tableViewer.setLabelProvider(new RuntimeLoggingTableLabelProvider()); + _tableViewer.setSorter(tableSorter); + _table.setSortColumn(_table.getColumn(0)); + _table.setSortDirection(SWT.UP); + _table.addMouseListener(new MouseListener() + { + public void mouseDoubleClick(MouseEvent event) + { + editLoggerLevel(_table.getShell()); + } + + public void mouseDown(MouseEvent e){} + public void mouseUp(MouseEvent e){} + }); + + final Button logLevelEditButton = _toolkit.createButton(effectiveRuntimeLoggerLevelsGroup, "Edit Selected Logger(s)...", SWT.PUSH); + logLevelEditButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); + logLevelEditButton.setEnabled(false); + logLevelEditButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + editLoggerLevel(logLevelEditButton.getShell()); + } + }); + + _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + logLevelEditButton.setEnabled(true); + } + else + { + logLevelEditButton.setEnabled(false); + } + } + }); + + Composite attributesComposite = _toolkit.createComposite(_paramsComposite); + gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + attributesComposite.setLayoutData(gridData); + gridLayout = new GridLayout(3,false); + attributesComposite.setLayout(gridLayout); + + Group runtimeRootLoggerGroup = new Group(attributesComposite, SWT.SHADOW_NONE); + runtimeRootLoggerGroup.setBackground(attributesComposite.getBackground()); + runtimeRootLoggerGroup.setText("Runtime RootLogger Level"); + gridData = new GridData(SWT.LEFT, SWT.TOP, true, false); + runtimeRootLoggerGroup.setLayoutData(gridData); + runtimeRootLoggerGroup.setLayout(new GridLayout(2,false)); + + _runtimeRootLoggerLevelLabel = _toolkit.createLabel(runtimeRootLoggerGroup, "-"); + _runtimeRootLoggerLevelLabel.setFont(ApplicationRegistry.getFont(FONT_BOLD)); + _runtimeRootLoggerLevelLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); + + final Button runtimeRootLoggerLevelButton = _toolkit.createButton(runtimeRootLoggerGroup, "Edit ...", SWT.PUSH); + runtimeRootLoggerLevelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false)); + runtimeRootLoggerLevelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + editRootLoggerLevel(runtimeRootLoggerLevelButton.getShell()); + } + }); + } + + private void editLoggerLevel(Shell parent) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + int[] selectedIndices = _table.getSelectionIndices(); + + final ArrayList<String> selectedLoggers = new ArrayList<String>(); + + for(int index = 0; index < selectedIndices.length ; index++) + { + CompositeData selectedLogger = (CompositeData)_table.getItem(selectedIndices[index]).getData(); + String user = (String) selectedLogger.get(LOGGER_NAME); + selectedLoggers.add(user); + } + + final Shell shell = ViewUtility.createModalDialogShell(parent, "Set Runtime Logger Level(s)"); + + _toolkit.createLabel(shell, "Logger(s): ").setBackground(shell.getBackground()); + + final Text headerText = new Text(shell, SWT.WRAP | SWT.V_SCROLL | SWT.BORDER ); + headerText.setEditable(false); + GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); + data.minimumHeight = 125; + data.heightHint = 125; + data.minimumWidth = 575; + data.widthHint = 575; + headerText.setLayoutData(data); + + String lineSeperator = System.getProperty("line.separator"); + for(String loggerName : selectedLoggers) + { + headerText.append(loggerName + lineSeperator); + } + headerText.setSelection(0); + + Composite levelComp = _toolkit.createComposite(shell); + levelComp.setBackground(shell.getBackground()); + levelComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + levelComp.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(levelComp,"Level: ").setBackground(levelComp.getBackground()); + final Combo levelCombo = new Combo (levelComp, SWT.READ_ONLY ); + levelCombo.setItems(_availableLoggerLevels); + levelCombo.select(0); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String level = levelCombo.getItem(levelCombo.getSelectionIndex()).toString(); + + shell.close(); + + try + { + HashMap<String,Boolean> results = new HashMap<String,Boolean>(); + + //perform the updates, save the results. + for(String logger : selectedLoggers) + { + boolean result = _lmmb.setRuntimeLoggerLevel(logger, level); + results.put(logger, result); + } + + //categorise the overall result + boolean overallResult = true; + for(boolean result : results.values()) + { + if (!result) + { + overallResult = false; + } + } + + //output the result to status bar if all succeed, and dialogue if not + if(overallResult) + { + ViewUtility.operationResultFeedback(overallResult, "Updated Runtime Logger Level(s)", null); + } + else + { + String failedToSetLevelOfLoggers = ""; + for(String logger : results.keySet()) + { + if(!results.get(logger)) + { + failedToSetLevelOfLoggers = failedToSetLevelOfLoggers.concat(logger + ", "); + } + } + + //cut off last ", " + int lastIndex = failedToSetLevelOfLoggers.lastIndexOf(','); + if (lastIndex != -1) + { + failedToSetLevelOfLoggers = failedToSetLevelOfLoggers.substring(0, lastIndex); + } + + ViewUtility.operationResultFeedback(overallResult, null, + "Failed to update Runtime Logger Level(s): " + + failedToSetLevelOfLoggers); + } + } + catch(Exception e3) + { + ViewUtility.operationFailedStatusBarMessage("Error updating Runtime Logger Level(s)"); + MBeanUtility.handleException(_mbean, e3); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + } + + private void editRootLoggerLevel(Shell parent) + { + final Shell shell = ViewUtility.createModalDialogShell(parent, "Runtime RootLogger Level"); + + Composite levelComp = _toolkit.createComposite(shell); + levelComp.setBackground(shell.getBackground()); + levelComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + levelComp.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(levelComp,"RootLogger level: ").setBackground(levelComp.getBackground()); + final Combo levelCombo = new Combo (levelComp, SWT.READ_ONLY ); + levelCombo.setItems(_availableLoggerLevels); + levelCombo.select(0); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String selection = levelCombo.getItem(levelCombo.getSelectionIndex()).toString(); + shell.dispose(); + + try + { + boolean result = _lmmb.setRuntimeRootLoggerLevel(selection); + ViewUtility.operationResultFeedback(result, + "Updated Runtime RootLogger Level", "Failed to update Runtime Logger Level"); + } + catch(Exception e4) + { + ViewUtility.operationFailedStatusBarMessage("Error updating Runtime Logger Level"); + MBeanUtility.handleException(_mbean, e4); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + /** + * Label Provider class for the RuntimeLoggers table viewer + */ + public class RuntimeLoggingTableLabelProvider extends LabelProvider implements ITableLabelProvider, IColorProvider + { + + @Override + public String getColumnText(Object element, int columnIndex) + { + switch (columnIndex) + { + case 0 : // logger name column + return (String) ((CompositeDataSupport) element).get(LOGGER_NAME); + case 1 : // logger level column + return (String) ((CompositeDataSupport) element).get(LOGGER_LEVEL); + default : + return "-"; + } + } + + @Override + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + @Override + public Color getBackground(Object element) + { + return null; + } + + @Override + public Color getForeground(Object element) + { + String loggerName = (String) ((CompositeData) element).get(LOGGER_NAME); + if(_configFileLoggerNames.contains(loggerName)) + { + return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE); + } + else + { + return null; + } + } + + + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/queue/QueueOperationsTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/queue/QueueOperationsTabControl.java new file mode 100644 index 0000000000..ee6bd3522b --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/queue/QueueOperationsTabControl.java @@ -0,0 +1,1111 @@ +/* + * + * 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.queue; + +import static org.apache.qpid.management.common.mbeans.ManagedQueue.MSG_AMQ_ID; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.MSG_HEADER; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.MSG_QUEUE_POS; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.MSG_REDELIVERED; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.MSG_SIZE; +import static org.apache.qpid.management.ui.Constants.CONSOLE_IMAGE; +import static org.apache.qpid.management.ui.Constants.RESULT; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.TabularDataSupport; + +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.common.mbeans.ManagedQueue; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.NumberVerifyListener; +import org.apache.qpid.management.ui.views.TabControl; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; + + +/** + * Control class for the Queue mbean Operations tab. + */ +public class QueueOperationsTabControl extends TabControl +{ + private FormToolkit _toolkit; + private ScrolledForm _form; + private Table _table = null; + private TableViewer _tableViewer = null; + private Composite _paramsComposite = null; + + private ApiVersion _ApiVersion; + + private Text _fromMsgText; + private Text _toMsgText; + private static final String FROM_DEFAULT = "1"; + private static final String TO_DEFAULT = "50"; + private long _interval = 50; //(to-from)+1 + private Long _fromMsg = new Long(FROM_DEFAULT); + private Long _toMsg = new Long(TO_DEFAULT); + + private TabularDataSupport _messages = null; + private ManagedQueue _qmb; + + private Button _previousButton; + private Button _nextButton; + + public QueueOperationsTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc) + { + super(tabFolder); + _mbean = mbean; + _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion(); + _qmb = (ManagedQueue) MBeanServerInvocationHandler.newProxyInstance(mbsc, + mbean.getObjectName(), ManagedQueue.class, false); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createScrolledForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + createComposites(); + createWidgets(); + } + + private void createComposites() + { + _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + _paramsComposite.setLayout(new GridLayout()); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + _table.setFocus(); + } + + @Override + public void refresh(ManagedBean mbean) + { + _messages = null; + try + { + if(_ApiVersion.greaterThanOrEqualTo(1, 3)) + { //broker supports Qpid JMX API 1.3 and takes Long values + + //gather a list of all messages on the queue for display and selection + _messages = (TabularDataSupport) _qmb.viewMessages(_fromMsg,_toMsg); + } + else + { //broker supports Qpid JMX API 1.2 or below and takes int values + + if(_toMsg > Integer.MAX_VALUE || _toMsg > Integer.MAX_VALUE) + { + ViewUtility.popupErrorMessage("Error", "This broker only supports viewing up to message " + Integer.MAX_VALUE); + _tableViewer.setInput(null); + return; + } + + //gather a list of all messages on the queue for display and selection + _messages = (TabularDataSupport) _qmb.viewMessages(_fromMsg.intValue(), _toMsg.intValue()); + } + } + catch (Exception e) + { + MBeanUtility.handleException(mbean,e); + } + + _tableViewer.setInput(_messages); + + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + private void createWidgets() + { + Group messagesGroup = new Group(_paramsComposite, SWT.SHADOW_NONE | SWT.SCROLL_LINE); + messagesGroup.setBackground(_paramsComposite.getBackground()); + messagesGroup.setText("Messages"); + messagesGroup.setLayout(new GridLayout()); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + messagesGroup.setLayoutData(gridData); + + //from and to fields for selecting the viewing range + Composite viewMessageRangeComposite = _toolkit.createComposite(messagesGroup); + gridData = new GridData(SWT.LEFT, SWT.FILL, false, false); + viewMessageRangeComposite.setLayoutData(gridData); + viewMessageRangeComposite.setLayout(new GridLayout(8,false)); + + _toolkit.createLabel(viewMessageRangeComposite, "Queue pos: "); + _fromMsgText = new Text(viewMessageRangeComposite, SWT.BORDER); + _fromMsgText.setText(FROM_DEFAULT); + gridData = new GridData(SWT.LEFT, SWT.FILL, false, false); + gridData.widthHint = 75; + _fromMsgText.setLayoutData(gridData); + _fromMsgText.addVerifyListener(new NumberVerifyListener()); + _fromMsgText.addKeyListener(new KeyAdapter() + { + public void keyPressed(KeyEvent event) + { + if (event.character == SWT.CR) + { + updateMessageInterval(); + } + } + }); + + _toolkit.createLabel(viewMessageRangeComposite, "to"); + + _toMsgText = new Text(viewMessageRangeComposite, SWT.BORDER); + _toMsgText.setText(TO_DEFAULT); + gridData = new GridData(SWT.LEFT, SWT.FILL, false, false); + gridData.widthHint = 75; + _toMsgText.setLayoutData(gridData); + _toMsgText.addVerifyListener(new NumberVerifyListener()); + _toMsgText.addKeyListener(new KeyAdapter() + { + public void keyPressed(KeyEvent event) + { + if (event.character == SWT.CR) + { + updateMessageInterval(); + } + } + }); + + final Button setButton = _toolkit.createButton(viewMessageRangeComposite, "Set", SWT.PUSH); + setButton.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false)); + setButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + updateMessageInterval(); + } + }); + + _toolkit.createLabel(viewMessageRangeComposite, " "); //spacer + + _previousButton = _toolkit.createButton(viewMessageRangeComposite, "< Prev " + _interval, SWT.PUSH); + _previousButton.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false)); + _previousButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + //make 'to' be 'from - 1' unless from is 1 (ie there are no previous messages) + if(_fromMsg > 1) + { + _toMsg = _fromMsg - 1; + _toMsgText.setText(_toMsg.toString()); + } + + //make 'from' be 'from - INTERVAL', or make it 1 if that would make it 0 or less + _fromMsg = (_fromMsg - _interval < 1) ? 1 : _fromMsg - _interval; + _fromMsgText.setText(_fromMsg.toString()); + + refresh(_mbean); + } + }); + + _nextButton = _toolkit.createButton(viewMessageRangeComposite, "Next " + _interval + " >", SWT.PUSH); + _nextButton.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false)); + _nextButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + //make 'from' be 'to + 1' unless 'to' is already Long.MAX_VALUE + if(_toMsg != Long.MAX_VALUE) + { + _fromMsg = _toMsg + 1; + _fromMsgText.setText(_fromMsg.toString()); + } + + //make 'to' be 'to + INTERVAL', or make it Long.MAX_VALUE if that would too large + _toMsg = (Long.MAX_VALUE - _toMsg > _interval) ? _toMsg + _interval : Long.MAX_VALUE; + _toMsgText.setText(_toMsg.toString()); + + refresh(_mbean); + } + }); + + //message table + Composite tableAndButtonsComposite = _toolkit.createComposite(messagesGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.minimumHeight = 180; + gridData.heightHint = 180; + tableAndButtonsComposite.setLayoutData(gridData); + tableAndButtonsComposite.setLayout(new GridLayout(2,false)); + + _table = new Table (tableAndButtonsComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _table.setLinesVisible (true); + _table.setHeaderVisible (true); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + _table.setLayoutData(data); + + _tableViewer = new TableViewer(_table); + final TableSorter tableSorter = new TableSorter(); + + String[] titles = {"AMQ ID", "Size(bytes)"}; + if(_ApiVersion.greaterThanOrEqualTo(1, 3)) + { + //if server management API is >= 1.3, show message's queue position + titles = new String[]{"AMQ ID", "Size(bytes)", "Queue Position"}; + } + + int[] bounds = { 175, 175, 140 }; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableColumn column = new TableColumn (_table, SWT.NONE); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _tableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _tableViewer.setContentProvider(new ContentProviderImpl()); + _tableViewer.setLabelProvider(new LabelProviderImpl()); + _tableViewer.setSorter(tableSorter); + _table.setSortColumn(_table.getColumn(0)); + _table.setSortDirection(SWT.UP); + + //Side Buttons + Composite buttonsComposite = _toolkit.createComposite(tableAndButtonsComposite); + gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + buttonsComposite.setLayoutData(gridData); + buttonsComposite.setLayout(new GridLayout()); + + final Button viewSelectedMsgButton = _toolkit.createButton(buttonsComposite, "View Message Content ...", SWT.PUSH); + viewSelectedMsgButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + viewSelectedMsgButton.setEnabled(false); + viewSelectedMsgButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + if (_table.getSelectionIndex() == -1) + { + return; + } + + viewMessageContent(); + } + }); + + if(_ApiVersion.lessThan(1, 3)) //if the server predates Qpid JMX API 1.3 + { + final Button deleteFirstMessageButton = _toolkit.createButton(buttonsComposite, "Delete 1st Unacquired Msg", SWT.PUSH); + deleteFirstMessageButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + deleteFirstMessageButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent se) + { + int response = ViewUtility.popupOkCancelConfirmationMessage("Delete 1st unacquired message", + "Delete 1st unacquired message on the queue?\n\n" + + "NOTE: Any ongoing consumer activity may mean this is " + + "not the first message listed in the table."); + if (response == SWT.OK) + { + try + { + _qmb.deleteMessageFromTop(); + ViewUtility.operationResultFeedback(null, "Deleted 1st unacquired message on the queue", null); + } + catch (Exception e) + { + ViewUtility.operationFailedStatusBarMessage("Error deleting 1st unacquired message on queue"); + MBeanUtility.handleException(_mbean, e); + } + + refresh(_mbean);; + } + } + }); + } + + final Button moveMessagesButton; + if(_ApiVersion.greaterThanOrEqualTo(1, 3)) + { + //If the server supports Qpid JMX API 1.3, show the move message button. + //This is being disabled for earlier brokers due to bugs affecting the result appearance + //and impacting on the ability of the source queues to deliver further messages. + + moveMessagesButton = _toolkit.createButton(buttonsComposite, "Move Message(s) ...", SWT.PUSH); + + moveMessagesButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + moveMessagesButton.setEnabled(false); + moveMessagesButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + if (_table.getSelectionIndex() == -1) + { + return; + } + + moveOrCopyMessages(moveMessagesButton.getShell(), QueueOperations.MOVE); + } + }); + } + else + { + moveMessagesButton = null; + } + + final Button copyMessagesButton; + if(_ApiVersion.greaterThanOrEqualTo(1, 3))//if the server supports Qpid JMX API 1.3 + { + copyMessagesButton= _toolkit.createButton(buttonsComposite, "Copy Message(s) ...", SWT.PUSH); + copyMessagesButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + copyMessagesButton.setEnabled(false); + copyMessagesButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + if (_table.getSelectionIndex() == -1) + { + return; + } + + moveOrCopyMessages(copyMessagesButton.getShell(), QueueOperations.COPY); + } + }); + } + else + { + copyMessagesButton = null; + } + + final Button deleteMessagesButton; + if(_ApiVersion.greaterThanOrEqualTo(1, 3))//if the server supports Qpid JMX API 1.3 + { + deleteMessagesButton = _toolkit.createButton(buttonsComposite, "Delete Message(s) ...", SWT.PUSH); + deleteMessagesButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + deleteMessagesButton.setEnabled(false); + deleteMessagesButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + if (_table.getSelectionIndex() == -1) + { + return; + } + + deleteMessages(deleteMessagesButton.getShell()); + } + }); + } + else + { + deleteMessagesButton = null; + } + + final Button clearQueueButton = _toolkit.createButton(buttonsComposite, "Clear Queue", SWT.PUSH); + clearQueueButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + clearQueueButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int response = ViewUtility.popupOkCancelConfirmationMessage("Clear Queue", + "Clear queue ?"); + if (response == SWT.OK) + { + try + { + if(_ApiVersion.greaterThanOrEqualTo(1, 3)) + { + //Qpid JMX API 1.3+, returns the number of messages deleted + Long numDeleted = _qmb.clearQueue(); + String message = "Queue cleared of " + numDeleted + + " non-acquired message" + (numDeleted == 1 ? "": "s"); + + ViewUtility.operationResultFeedback(null, message, null); + } + else + { + //Qpid JMX API 1.2 or below, void return + _qmb.clearQueue(); + ViewUtility.operationResultFeedback(null, "Queue cleared of non-acquired messages", null); + } + } + catch (Exception e2) + { + ViewUtility.operationFailedStatusBarMessage("Error clearing Queue"); + MBeanUtility.handleException(_mbean, e2); + } + + refresh(_mbean);; + } + } + }); + + _toolkit.createLabel(messagesGroup, "Message Header: "); + + //Redelivered status and header + Composite headerEtcComposite = _toolkit.createComposite(messagesGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + headerEtcComposite.setLayoutData(gridData); + headerEtcComposite.setLayout(new GridLayout()); + + final Text headerText = new Text(headerEtcComposite, SWT.WRAP | SWT.BORDER | SWT.V_SCROLL); + headerText.setText("Select a message to view its header."); + headerText.setEditable(false); + data = new GridData(SWT.LEFT, SWT.TOP, false, false); + data.minimumHeight = 210; + data.heightHint = 210; + data.minimumWidth = 500; + data.widthHint = 500; + headerText.setLayoutData(data); + + Composite redeliveryComposite = _toolkit.createComposite(headerEtcComposite); + redeliveryComposite.setLayout(new GridLayout(2,false)); + data = new GridData(SWT.LEFT, SWT.FILL, false, false); + data.minimumWidth = 150; + data.widthHint = 150; + redeliveryComposite.setLayoutData(data); + + _toolkit.createLabel(redeliveryComposite, "Redelivered: "); + final Text redeliveredText = new Text(redeliveryComposite, SWT.BORDER); + redeliveredText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + redeliveredText.setText("-"); + redeliveredText.setEditable(false); + + //listener for double clicking to view message content + _table.addMouseListener(new MouseListener() + { + // MouseListener implementation + public void mouseDoubleClick(MouseEvent event) + { + viewMessageContent(); + } + + public void mouseDown(MouseEvent e){} + public void mouseUp(MouseEvent e){} + }); + + //selection listener to enable and disable buttons, update header and redelivered info + _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex == -1) + { + headerText.setText("Select a message to view its header."); + redeliveredText.setText("-"); + viewSelectedMsgButton.setEnabled(false); + if(moveMessagesButton != null) + { + moveMessagesButton.setEnabled(false); + } + if(copyMessagesButton != null) + { + copyMessagesButton.setEnabled(false); + } + if(deleteMessagesButton != null) + { + deleteMessagesButton.setEnabled(false); + } + + return; + } + else + { + if(moveMessagesButton != null) + { + moveMessagesButton.setEnabled(true); + } + if(copyMessagesButton != null) + { + copyMessagesButton.setEnabled(true); + } + if(deleteMessagesButton != null) + { + deleteMessagesButton.setEnabled(true); + } + + final CompositeData selectedMsg = (CompositeData)_table.getItem(selectionIndex).getData(); + Boolean redelivered = (Boolean) selectedMsg.get(MSG_REDELIVERED); + redeliveredText.setText(redelivered.toString()); + + String[] msgHeader = (String[]) selectedMsg.get(MSG_HEADER); + headerText.setText(""); + String lineSeperator = System.getProperty("line.separator"); + int size = msgHeader.length; + for(int i=0; i < size; i++) + { + headerText.append(msgHeader[i]); + if(!(i == size - 1)) + { + headerText.append(lineSeperator); + } + } + headerText.setSelection(0); + } + + if (_table.getSelectionCount() > 1) + { + viewSelectedMsgButton.setEnabled(false); + } + else + { + viewSelectedMsgButton.setEnabled(true); + } + + } + }); + + } + + /** + * Content Provider class for the table viewer + */ + private static class ContentProviderImpl implements IStructuredContentProvider + { + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + public Object[] getElements(Object parent) + { + Collection<Object> rowCollection = ((TabularDataSupport) parent).values(); + + return rowCollection.toArray(); + } + } + + /** + * Label Provider class for the table viewer + */ + private static class LabelProviderImpl extends LabelProvider implements ITableLabelProvider + { + public String getColumnText(Object element, int columnIndex) + { + switch (columnIndex) + { + case 0 : // msg id column + return String.valueOf(((CompositeDataSupport) element).get(MSG_AMQ_ID)); + case 1 : // msg size column + return String.valueOf(((CompositeDataSupport) element).get(MSG_SIZE)); + case 2 : // msg position in queue + return String.valueOf(((CompositeDataSupport) element).get(MSG_QUEUE_POS)); + default : + return "-"; + } + } + + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + } + + /** + * Sorter class for the table viewer. + * + */ + public static class TableSorter extends ViewerSorter + { + private int column; + private static final int ASCENDING = 0; + private static final int DESCENDING = 1; + + private int direction = DESCENDING; + + public TableSorter() + { + this.column = 0; + direction = ASCENDING; + } + + public void setColumn(int column) + { + if (column == this.column) + { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } + else + { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + CompositeData msg1 = (CompositeData) e1; + CompositeData msg2 = (CompositeData) e2; + + int comparison = 0; + switch(column) + { + case 0: + comparison = ((Long) msg1.get(MSG_AMQ_ID)).compareTo((Long)msg2.get(MSG_AMQ_ID)); + break; + case 1: + comparison = ((Long) msg1.get(MSG_SIZE)).compareTo((Long)msg2.get(MSG_SIZE)); + break; + case 2: + comparison = ((Long) msg1.get(MSG_QUEUE_POS)).compareTo((Long)msg2.get(MSG_QUEUE_POS)); + break; + default: + comparison = 0; + } + // If descending order, flip the direction + if(direction == DESCENDING) + { + comparison = -comparison; + } + return comparison; + } + } + + private void updateMessageInterval() + { + Long from; + try + { + from = Long.valueOf(_fromMsgText.getText()); + } + catch(Exception e1) + { + ViewUtility.popupErrorMessage("Invalid Value", "Please enter a valid 'from' number"); + return; + } + + Long to; + try + { + to = Long.valueOf(_toMsgText.getText()); + } + catch(Exception e1) + { + ViewUtility.popupErrorMessage("Invalid Value", "Please enter a valid 'to' number"); + return; + } + + _fromMsg = from; + _toMsg = to; + + _interval = (to - from) + 1; + _previousButton.setText("< Prev " + _interval); + _nextButton.setText("Next " + _interval + " >"); + + refresh(_mbean); + } + + private void viewMessageContent() + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + try + { + final CompositeData selectedMsg = (CompositeData)_table.getItem(selectionIndex).getData(); + Long msgId = (Long) selectedMsg.get(MSG_AMQ_ID); + + Object result = _qmb.viewMessageContent(msgId); + + populateResults(result); + } + catch (Exception e3) + { + MBeanUtility.handleException(_mbean, e3); + } + } + } + + private void populateResults(Object result) + { + Display display = Display.getCurrent(); + int width = 610; + int height = 400; + Shell shell = ViewUtility.createPopupShell(RESULT, width, height); + shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE)); + ViewUtility.populateCompositeWithData(_toolkit, shell, result); + + shell.open(); + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + { + display.sleep(); + } + } + shell.dispose(); + } + + private void moveOrCopyMessages(final Shell parent, final QueueOperations op) + { + final ArrayList<Long> rangeStarts = new ArrayList<Long>(); + final ArrayList<Long> rangeEnds = new ArrayList<Long>(); + + gatherSelectedAMQMsgIDRanges(rangeStarts,rangeEnds); + String rangeString = getRangesString(rangeStarts,rangeEnds); + + String windowTitle; + String dialogueMessage; + final String feedBackMessage; + final String failureFeedBackMessage; + + if(op.equals(QueueOperations.MOVE)) + { + windowTitle = "Move Messages"; + dialogueMessage = "Move message(s) with AMQ ID:"; + feedBackMessage = "Messages moved"; + failureFeedBackMessage = "Error moving messages"; + } + else + { + windowTitle = "Copy Messages"; + dialogueMessage = "Copy message(s) with AMQ ID:"; + feedBackMessage = "Messages copied"; + failureFeedBackMessage = "Error copying messages"; + } + + final Shell shell = ViewUtility.createModalDialogShell(parent, windowTitle); + + Composite idComposite = _toolkit.createComposite(shell, SWT.NONE); + idComposite.setBackground(shell.getBackground()); + idComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + idComposite.setLayout(new GridLayout()); + + _toolkit.createLabel(idComposite,dialogueMessage).setBackground(shell.getBackground()); + _toolkit.createLabel(idComposite,rangeString).setBackground(shell.getBackground()); + + Composite destinationComposite = _toolkit.createComposite(shell, SWT.NONE); + destinationComposite.setBackground(shell.getBackground()); + destinationComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + destinationComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(destinationComposite,"To Queue:").setBackground(shell.getBackground()); + final Combo destinationCombo = new Combo(destinationComposite,SWT.NONE | SWT.READ_ONLY); + destinationCombo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + List<String> queueList = ApplicationRegistry.getServerRegistry(_mbean).getQueueNames(_mbean.getVirtualHostName()); + queueList.remove(_mbean.getName()); + + if(queueList.size() == 0) + { + destinationCombo.setItems(new String[]{"No other queues available"}); + okButton.setEnabled(false); + } + else + { + Collections.sort(queueList); + destinationCombo.setItems(queueList.toArray(new String[0])); + } + destinationCombo.select(0); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String destQueue = destinationCombo.getItem(destinationCombo.getSelectionIndex()).toString(); + shell.dispose(); + + try + { + for(int i=0 ; i < rangeStarts.size() ; i++) + { + Long from = rangeStarts.get(i); + Long to = rangeEnds.get(i); + + switch(op) + { + case COPY: + _qmb.copyMessages(Long.valueOf(from), Long.valueOf(to), destQueue); + break; + case MOVE: + _qmb.moveMessages(Long.valueOf(from), Long.valueOf(to), destQueue); + break; + } + } + + ViewUtility.operationResultFeedback(null, feedBackMessage, null); + } + catch (Exception e4) + { + ViewUtility.operationFailedStatusBarMessage(failureFeedBackMessage); + MBeanUtility.handleException(_mbean, e4); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private void deleteMessages(final Shell parent) + { + final ArrayList<Long> rangeStarts = new ArrayList<Long>(); + final ArrayList<Long> rangeEnds = new ArrayList<Long>(); + + gatherSelectedAMQMsgIDRanges(rangeStarts,rangeEnds); + String rangeString = getRangesString(rangeStarts,rangeEnds); + + final Shell shell = ViewUtility.createModalDialogShell(parent, "Delete Messages"); + + Composite idComposite = _toolkit.createComposite(shell, SWT.NONE); + idComposite.setBackground(shell.getBackground()); + idComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + idComposite.setLayout(new GridLayout()); + + _toolkit.createLabel(idComposite,"Delete message(s) with AMQ ID:").setBackground(shell.getBackground()); + _toolkit.createLabel(idComposite,rangeString).setBackground(shell.getBackground()); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + + try + { + for(int i=0 ; i < rangeStarts.size() ; i++) + { + Long from = rangeStarts.get(i); + Long to = rangeEnds.get(i); + + _qmb.deleteMessages(Long.valueOf(from), Long.valueOf(to)); + } + + ViewUtility.operationResultFeedback(null, "Messages deleted", null); + } + catch (Exception e4) + { + ViewUtility.operationFailedStatusBarMessage("Error deleting messages"); + MBeanUtility.handleException(_mbean, e4); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private void gatherSelectedAMQMsgIDRanges(ArrayList<Long> starts, ArrayList<Long> ends) + { + SortedSet<Long> amqIDs = new TreeSet<Long>(); + + for(Integer i : _table.getSelectionIndices()) + { + CompositeData selectedMsg = (CompositeData)_table.getItem(i).getData(); + amqIDs.add((Long)selectedMsg.get(MSG_AMQ_ID)); + } + + //initialise the first range + Long start = amqIDs.first(); + Long end = amqIDs.first(); + + for(Long id : amqIDs) + { + if(id == amqIDs.first()) + { + //skip first check, already initialised range + continue; + } + + if(id == end +1) + { + //part of previous range, append + end = id; + } + else + { + //not in previous range, record existing start and end msg id values + starts.add(start); + ends.add(end); + + //begin new range with this msg id + start = id; + end = id; + } + } + + //record the last range created + starts.add(start); + ends.add(end); + } + + private String getRangesString(ArrayList<Long> starts, ArrayList<Long> ends) + { + String idRangesString = ""; + + for(int i=0 ; i < starts.size() ; i++) + { + long start = starts.get(i); + long end = ends.get(i); + + if(i != 0) + { + idRangesString = idRangesString.concat(", "); + } + + if(start == end) + { + idRangesString = idRangesString.concat(String.valueOf(starts.get(i))); + } + else + { + idRangesString = idRangesString.concat(starts.get(i) + "-" + ends.get(i)); + } + } + + return idRangesString.concat("."); + } + + private enum QueueOperations + { + MOVE, + COPY; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ConnectionTypeTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ConnectionTypeTabControl.java new file mode 100644 index 0000000000..f1f7b07b6f --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ConnectionTypeTabControl.java @@ -0,0 +1,50 @@ +/* + * + * 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.type; + +import java.util.List; + +import static org.apache.qpid.management.ui.Constants.CONNECTION; + +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.ManagedServer; +import org.eclipse.swt.widgets.TabFolder; + +/** + * Controller class, which takes care of displaying appropriate information and widgets for Connections. + * This allows user to select Connections and add those to the navigation view + */ + +public class ConnectionTypeTabControl extends MBeanTypeTabControl +{ + + public ConnectionTypeTabControl(TabFolder tabFolder, ManagedServer server, String virtualHost) + { + super(tabFolder, server, virtualHost, CONNECTION); + } + + @Override + protected List<ManagedBean> getMbeans() + { + return _serverRegistry.getConnections(_virtualHost); + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ExchangeTypeTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ExchangeTypeTabControl.java new file mode 100644 index 0000000000..5d587c7158 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/ExchangeTypeTabControl.java @@ -0,0 +1,45 @@ +/* + * + * 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.type; + +import java.util.List; + +import static org.apache.qpid.management.ui.Constants.EXCHANGE; + +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.ManagedServer; +import org.eclipse.swt.widgets.TabFolder; + +public class ExchangeTypeTabControl extends MBeanTypeTabControl +{ + + public ExchangeTypeTabControl(TabFolder tabFolder, ManagedServer server, String virtualHost) + { + super(tabFolder, server, virtualHost, EXCHANGE); + } + + @Override + protected List<ManagedBean> getMbeans() + { + return _serverRegistry.getExchanges(_virtualHost); + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/MBeanTypeTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/MBeanTypeTabControl.java new file mode 100644 index 0000000000..a4574b8d22 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/MBeanTypeTabControl.java @@ -0,0 +1,456 @@ +/* + * + * 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.type; + + +import java.util.ArrayList; +import java.util.List; + +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.ManagedServer; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.JMXServerRegistry; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.MBeanView; +import org.apache.qpid.management.ui.views.NavigationView; +import org.apache.qpid.management.ui.views.TabControl; + +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.widgets.Form; +import org.eclipse.ui.forms.widgets.FormToolkit; + +public abstract class MBeanTypeTabControl extends TabControl +{ + protected FormToolkit _toolkit; + protected Form _form; + protected Table _table = null; + protected TableViewer _tableViewer = null; + + protected List<ManagedBean> _mbeans = null; + protected String _type; + protected ApiVersion _ApiVersion; + protected JMXManagedObject _vhostMbean; + protected String _virtualHost; + protected JMXServerRegistry _serverRegistry; + protected Composite _tableComposite; + protected Button _favouritesButton; + protected Button _openButton; + + public MBeanTypeTabControl(TabFolder tabFolder, ManagedServer server, String virtualHost, String type) + { + super(tabFolder); + _virtualHost = virtualHost; + _serverRegistry = (JMXServerRegistry) ApplicationRegistry.getServerRegistry(server); + _ApiVersion = _serverRegistry.getManagementApiVersion(); + _vhostMbean = (JMXManagedObject) _serverRegistry.getVirtualHostManagerMBean(_virtualHost); + _type = type; + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + init(); + createWidgets(); + } + + protected void init() + { + + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + _table.setFocus(); + } + + public void refresh() + { + refresh(null); + } + + + @Override + public void refresh(ManagedBean mbean) + { + _mbeans = getMbeans(); + + _tableViewer.setInput(_mbeans); + + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + protected abstract List<ManagedBean> getMbeans(); + + protected void createTable() + { + _table = new Table (_tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _table.setLinesVisible (true); + _table.setHeaderVisible (true); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + _table.setLayoutData(data); + + _tableViewer = new TableViewer(_table); + final TableSorter tableSorter = new TableSorter(); + + String[] titles = { "Name"}; + int[] bounds = { 310}; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE); + final TableColumn column = viewerColumn.getColumn(); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _tableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _tableViewer.setContentProvider(new ContentProviderImpl()); + _tableViewer.setLabelProvider(new LabelProviderImpl()); + _tableViewer.setSorter(tableSorter); + _table.setSortColumn(_table.getColumn(0)); + _table.setSortDirection(SWT.UP); + + addTableListeners(); + } + + protected void addTableListeners() + { + _favouritesButton.setEnabled(false); + _openButton.setEnabled(false); + + _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex == -1) + { + _favouritesButton.setEnabled(false); + _openButton.setEnabled(false); + return; + } + else + { + _favouritesButton.setEnabled(true); + } + + if(_table.getSelectionCount() > 1) + { + _openButton.setEnabled(false); + } + else + { + _openButton.setEnabled(true); + } + } + }); + + _table.addMouseListener(new MouseListener() + { + // MouseListener implementation + public void mouseDoubleClick(MouseEvent event) + { + openMBean(); + } + + public void mouseDown(MouseEvent e){} + public void mouseUp(MouseEvent e){} + }); + } + + + private void createWidgets() + { + Composite mainComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + mainComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + mainComposite.setLayout(new GridLayout()); + + Composite buttonComposite = _toolkit.createComposite(mainComposite, SWT.NONE); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + buttonComposite.setLayoutData(gridData); + buttonComposite.setLayout(new GridLayout(2,true)); + + _favouritesButton = _toolkit.createButton(buttonComposite, + "<-- Add " + _type + "(s) to favourites", SWT.PUSH); + gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false); + _favouritesButton.setLayoutData(gridData); + _favouritesButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + addMBeanToFavourites(); + } + }); + + _openButton = _toolkit.createButton(buttonComposite, "Open selected " + _type, SWT.PUSH); + gridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false); + _openButton.setLayoutData(gridData); + _openButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + openMBean(); + } + }); + + _tableComposite = _toolkit.createComposite(mainComposite); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + _tableComposite.setLayoutData(gridData); + _tableComposite.setLayout(new GridLayout(1,false)); + + createTable(); + + createLowerAreaButton(mainComposite); + } + + protected void createLowerAreaButton(Composite parent) + { + + } + + /** + * Content Provider class for the table viewer + */ + private static class ContentProviderImpl implements IStructuredContentProvider + { + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + @SuppressWarnings("unchecked") + public Object[] getElements(Object parent) + { + return ((List<ManagedBean>) parent).toArray(); + } + } + + /** + * Label Provider class for the table viewer + */ + private static class LabelProviderImpl extends LabelProvider implements ITableLabelProvider + { + public String getColumnText(Object element, int columnIndex) + { + switch (columnIndex) + { + case 0 : // name column + return ((ManagedBean) element).getName(); + default: + return "-"; + } + } + + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + } + + /** + * Sorter class for the table viewer. + * + */ + private static class TableSorter extends ViewerSorter + { + private int column; + private static final int ASCENDING = 0; + private static final int DESCENDING = 1; + + private int direction; + + public TableSorter() + { + this.column = 0; + direction = ASCENDING; + } + + public void setColumn(int column) + { + if(column == this.column) + { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } + else + { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + ManagedBean mbean1 = (ManagedBean) e1; + ManagedBean mbean2 = (ManagedBean) e2; + + int comparison = 0; + switch(column) + { + case 0: + comparison = mbean1.getName().compareTo(mbean2.getName()); + break; + default: + comparison = 0; + } + // If descending order, flip the direction + if(direction == DESCENDING) + { + comparison = -comparison; + } + return comparison; + } + } + + protected void addMBeanToFavourites() + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex == -1) + { + return; + } + + int[] selectedIndices = _table.getSelectionIndices(); + + ArrayList<ManagedBean> selectedMBeans = new ArrayList<ManagedBean>(); + + for(int index = 0; index < selectedIndices.length ; index++) + { + ManagedBean selectedMBean = (ManagedBean)_table.getItem(selectedIndices[index]).getData(); + selectedMBeans.add(selectedMBean); + } + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + NavigationView view = (NavigationView)window.getActivePage().findView(NavigationView.ID); + + ManagedBean bean = null; + try + { + for(ManagedBean mbean: selectedMBeans) + { + view.addManagedBean(mbean); + } + } + catch (Exception ex) + { + MBeanUtility.handleException(bean, ex); + } + } + + protected void openMBean() + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex == -1) + { + return; + } + + final ManagedBean selectedMBean = (ManagedBean)_table.getItem(selectionIndex).getData(); + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID); + try + { + view.openMBean(selectedMBean); + } + catch (Exception ex) + { + MBeanUtility.handleException(selectedMBean, ex); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/QueueTypeTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/QueueTypeTabControl.java new file mode 100644 index 0000000000..406ef08326 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/QueueTypeTabControl.java @@ -0,0 +1,786 @@ +/* + * + * 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.type; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Semaphore; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; + +import static org.apache.qpid.management.ui.ApplicationRegistry.DATA_DIR; +import static org.apache.qpid.management.ui.Constants.QUEUE; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_NAME; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_ACTIVE_CONSUMER_COUNT; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_AUTODELETE; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_CONSUMER_COUNT; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_DURABLE; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MAX_MSG_AGE; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MAX_MSG_COUNT; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MAX_MSG_SIZE; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MAX_QUEUE_DEPTH; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_MSG_COUNT; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_OWNER; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_QUEUE_DEPTH; +import static org.apache.qpid.management.common.mbeans.ManagedQueue.ATTR_RCVD_MSG_COUNT; + +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ManagedBean; +import org.apache.qpid.management.ui.ManagedServer; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.MBeanView; +import org.apache.qpid.management.ui.views.NavigationView; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.preference.PreferenceStore; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +public class QueueTypeTabControl extends MBeanTypeTabControl +{ + private MBeanServerConnection _mbsc; + private ManagedBroker _vhmb; + + private List<String> _selectedAttributes; + private PreferenceStore _preferences; + private Semaphore _tableViewerSemaphore = new Semaphore(1); + + private static final String APP_DIR = ApplicationRegistry.DATA_DIR; + private static final String INI_FILENAME = APP_DIR + File.separator + "qpidmc_queue_attributes.ini"; + private static final String INI_QUEUE_ATTRIBUES = "QueueAttributesSelection"; + + private static final ArrayList<String> FALLBACK_ATTRIBUTES_LIST = new ArrayList<String>(); + static + { + FALLBACK_ATTRIBUTES_LIST.add(ATTR_NAME); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_ACTIVE_CONSUMER_COUNT); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_AUTODELETE); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_CONSUMER_COUNT); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_DURABLE); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_MAX_MSG_AGE); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_MAX_MSG_COUNT); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_MAX_MSG_SIZE); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_MAX_QUEUE_DEPTH); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_MSG_COUNT); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_OWNER); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_QUEUE_DEPTH); + FALLBACK_ATTRIBUTES_LIST.add(ATTR_RCVD_MSG_COUNT); + } + + private static final Map<String, Integer> DEFAULT_COLUMN_WIDTHS = new HashMap<String,Integer>(); + static + { + DEFAULT_COLUMN_WIDTHS.put(ATTR_NAME, 215); + DEFAULT_COLUMN_WIDTHS.put(ATTR_OWNER,125); + DEFAULT_COLUMN_WIDTHS.put(ATTR_QUEUE_DEPTH,125); + } + + public QueueTypeTabControl(TabFolder tabFolder, ManagedServer server, String virtualHost) + { + super(tabFolder,server,virtualHost,QUEUE); + _mbsc = (MBeanServerConnection) _serverRegistry.getServerConnection(); + + //create a proxy for the VirtualHostManager mbean to use in retrieving the attribute names/values + _vhmb = MBeanServerInvocationHandler.newProxyInstance(_mbsc, + _vhostMbean.getObjectName(), ManagedBroker.class, false); + + } + + @Override + protected void init() + { + createIniFileIfNecessary(); + loadAttributePreferences(); + } + + /** + * Create the ini file if it doesn't already exist. + */ + public static void createIniFileIfNecessary() + { + File dir = new File(DATA_DIR); + if (!dir.exists()) + { + if(!dir.mkdir()) + { + System.err.println("Could not create application data directory " + DATA_DIR); + ViewUtility.popupErrorMessage("Error", "Fatal Error: Unable to create the application data directory: " + DATA_DIR); + System.exit(1); + } + } + + File file = new File(INI_FILENAME); + try + { + if (!file.exists()) + { + file.createNewFile(); + } + } + catch (IOException ex) + { + System.err.println("Error creating the configuration file " + INI_FILENAME); + ViewUtility.popupErrorMessage("Error", "Fatal Error: Unable to create the configuration file: " + INI_FILENAME); + System.exit(1); + } + } + + private void loadAttributePreferences() + { + _preferences = new PreferenceStore(INI_FILENAME); + List<String> attributesList = new ArrayList<String>(); + + //ensure the name is present, and first + attributesList.add(ManagedQueue.ATTR_NAME); + + //add any others from the file + try + { + _preferences.load(); + + String selectedAttributes = _preferences.getString(INI_QUEUE_ATTRIBUES); + if (selectedAttributes.length() != 0) + { + String[] attributes = selectedAttributes.split(","); + for (String attr : attributes) + { + if(attr.equals(ManagedQueue.ATTR_NAME)) + { + //the Name attribute is already present + continue; + } + + attributesList.add(attr); + } + } + } + catch (IOException e) + { + ViewUtility.popupErrorMessage("Error", "Unable to load previous attribute selections, defaulting to Name only"); + System.err.println(e); + } + + _selectedAttributes = attributesList; + } + + private void saveAttributePreferences() + { + String chosenAttributes = new String(); + + for(String attr : _selectedAttributes) + { + chosenAttributes = chosenAttributes.concat(attr) + ","; + } + //cut off last "," + int lastIndex = chosenAttributes.lastIndexOf(','); + if (lastIndex != -1) + { + chosenAttributes = chosenAttributes.substring(0,lastIndex); + } + + _preferences.putValue(INI_QUEUE_ATTRIBUES, chosenAttributes); + + try + { + _preferences.save(); + } + catch (IOException e) + { + ViewUtility.popupErrorMessage("Error", "Unable to save the attribute selection, choices will be lost at shutdown"); + System.err.println(e); + } + } + + @Override + public void refresh(ManagedBean mbean) + { + //Try locking. If we cant aquire the lock, dont bother getting new values. + //Either the attributes are being changed and these values would be out of date, + //or another thread is still in the process of refreshing + if(_tableViewerSemaphore.tryAcquire()) + { + try + { + List<List<Object>> values = null; + + if(_ApiVersion.greaterThanOrEqualTo(1, 3)) + { + //Qpid JMX API 1.3+, use this virtualhosts VirtualHostManager MBean + //to retrieve the attributes values requested for all queues at once + try + { + values = _vhmb.retrieveQueueAttributeValues(_selectedAttributes.toArray(new String[0])); + } + catch(Exception e) + { + MBeanUtility.handleException(_vhostMbean, e); + } + } + else + { + //Qpid JMX API 1.2 or below, use the local ManagedBeans and look + //up the attribute values for each queue individually + _mbeans = getMbeans(); + values = MBeanUtility.getQueueAttributes(_mbeans, _selectedAttributes.toArray(new String[0])); + } + + _tableViewer.setInput(values); + layout(); + } + finally + { + _tableViewerSemaphore.release(); + } + } + + } + + @Override + protected List<ManagedBean> getMbeans() + { + return _serverRegistry.getQueues(_virtualHost); + } + + private void clearTableComposite() + { + ViewUtility.disposeChildren(_tableComposite); + } + + @Override + protected void createTable() + { + _table = new Table (_tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _table.setLinesVisible (true); + _table.setHeaderVisible (true); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + _table.setLayoutData(data); + + _tableViewer = new TableViewer(_table); + + final QueueTableSorter tableSorter = new QueueTableSorter(); + + for (int i = 0; i < _selectedAttributes.size(); i++) + { + final int index = i; + final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE); + final TableColumn column = viewerColumn.getColumn(); + + String attrName = _selectedAttributes.get(i); + column.setMoveable(true); + column.setText(attrName); + column.pack(); + if(DEFAULT_COLUMN_WIDTHS.containsKey(attrName)) + { + //retrieve the desired default width + column.setWidth(DEFAULT_COLUMN_WIDTHS.get(attrName)); + } + else + { + //add padding for sort direction indicator + column.setWidth(column.getWidth() + 15); + } + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _tableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _tableViewer.setContentProvider(new QueueContentProviderImpl()); + _tableViewer.setLabelProvider(new QueueLabelProviderImpl()); + + _tableViewer.setUseHashlookup(true); + _tableViewer.setSorter(tableSorter); + _table.setSortColumn(_table.getColumn(0)); + _table.setSortDirection(SWT.UP); + + addTableListeners(); + } + + protected void createLowerAreaButton(Composite parent) + { + Composite lowerButtonComposite = _toolkit.createComposite(parent, SWT.NONE); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + lowerButtonComposite.setLayoutData(gridData); + lowerButtonComposite.setLayout(new GridLayout()); + + final Button attributesButton = _toolkit.createButton(lowerButtonComposite, "Select Attributes ...", SWT.PUSH); + gridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false); + attributesButton.setLayoutData(gridData); + attributesButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + chooseAttributes(attributesButton.getShell()); + } + }); + } + + private void chooseAttributes(final Shell parent) + { + + List<String> availableAttributes; + if(_ApiVersion.greaterThanOrEqualTo(1, 3)) + { + //Qpid JMX API 1.3+, request the current queue attributes names from the broker + try + { + availableAttributes = _vhmb.retrieveQueueAttributeNames(); + } + catch (IOException e) + { + availableAttributes = new ArrayList<String>(FALLBACK_ATTRIBUTES_LIST); + } + } + else + { + //Qpid JMX API 1.2 or below, use the falllback list of names. + availableAttributes = new ArrayList<String>(FALLBACK_ATTRIBUTES_LIST); + } + + + final List<String> chosenAttributes = new ArrayList<String>(); + + final Shell shell = ViewUtility.createModalDialogShell(parent, "Select Attributes"); + + Composite attributesComposite = _toolkit.createComposite(shell, SWT.NONE); + attributesComposite.setBackground(shell.getBackground()); + attributesComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + attributesComposite.setLayout(new GridLayout(2,false)); + + //add a selected-but-disabled check box for the Name attribute (its a mandatory attribute) + final Button nameCheckbox = new Button(attributesComposite, SWT.CHECK); + nameCheckbox.setText(ManagedQueue.ATTR_NAME); + nameCheckbox.setSelection(true); + nameCheckbox.setEnabled(false); + + for(String attr : availableAttributes) + { + if(attr.equals(ManagedQueue.ATTR_NAME)) + { + //Name attribute is mandatory and gets added to the front of the list later + continue; + } + + final Button attrButton = new Button(attributesComposite, SWT.CHECK); + attrButton.setText(attr); + + //if it was checked before, select it again now + if(_selectedAttributes.contains(attr)) + { + attrButton.setSelection(true); + chosenAttributes.add(attr); + } + + //add a selection listener to update the selected attribute list + attrButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + if(attrButton.getSelection()) + { + chosenAttributes.add(attrButton.getText()); + } + else + { + chosenAttributes.remove(attrButton.getText()); + } + } + }); + } + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + + //The Name attribute is mandatory, add it now, also + //ensuring it is left-most by placing it first in the list + List<String> newSelection = new ArrayList<String>(); + newSelection.add(ManagedQueue.ATTR_NAME); + + //now add all remaining choices in alphabetical order + Collections.sort(chosenAttributes); + newSelection.addAll(chosenAttributes); + + _tableViewerSemaphore.acquireUninterruptibly(); + try + { + _selectedAttributes = newSelection; + + clearTableComposite(); + createTable(); + saveAttributePreferences(); + } + finally + { + _tableViewerSemaphore.release(); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private String getQueueDepthString(Long value) + { + if(value == null) + { + return "-"; + } + + if (_ApiVersion.greaterThanOrEqualTo(1,2)) + { + //Qpid JMX API 1.2 or above, returns Bytes + return convertLongBytesToText(value); + } + else + { + //Qpid JMX API 1.1 or below, returns KB + double mb = 1024.0; + + if(value > mb) //MB + { + return String.format("%.3f", (Double)(value / mb)) + " MB"; + } + else //KB + { + return value + " KB"; + } + } + } + + private String convertLongBytesToText(Long value) + { + if(value == null) + { + return "-"; + } + + double mb = 1024.0 * 1024.0; + double kb = 1024.0; + + if(value >= mb) //MB + { + return String.format("%.3f", (Double)((double)value / mb)) + " MB"; + } + else if (value >= kb) //KB + { + return String.format("%.3f", (Double)((double)value / kb)) + " KB"; + } + else //Bytes + { + return value + " Bytes"; + } + } + + /** + * sorter class for the table viewer. + * + */ + private static class QueueTableSorter extends ViewerSorter + { + protected int column; + protected static final int ASCENDING = 0; + protected static final int DESCENDING = 1; + + protected int direction; + + public QueueTableSorter() + { + this.column = 0; + direction = ASCENDING; + } + + public void setColumn(int column) + { + if(column == this.column) + { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } + else + { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + @SuppressWarnings("unchecked") + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + List<Object> queue1 = (List<Object>) e1; + List<Object> queue2 = (List<Object>) e2; + + int comparison = 0; + switch(column) + { + default: + if(queue1.get(column) instanceof Comparable) + { + comparison = ((Comparable)queue1.get(column)).compareTo((Comparable) queue2.get(column)); + } + } + // If descending order, flip the direction + if(direction == DESCENDING) + { + comparison = -comparison; + } + return comparison; + } + } + + /** + * Content Provider class for the table viewer for Qpid JMX API 1.3 and above. + */ + private static class QueueContentProviderImpl implements IStructuredContentProvider + { + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + @SuppressWarnings("unchecked") + public Object[] getElements(Object parent) + { + return ((List<List<Object>>) parent).toArray(); + } + } + + /** + * Label Provider class for the table viewer for for Qpid JMX API 1.3 and above. + */ + private class QueueLabelProviderImpl extends LabelProvider implements ITableLabelProvider + { + @SuppressWarnings("unchecked") + public String getColumnText(Object element, int columnIndex) + { + List<Object> attributes = (List<Object>) element; + + switch (columnIndex) + { + default : + String attrName = _selectedAttributes.get(columnIndex); + + if(ATTR_QUEUE_DEPTH.equals(attrName)) + { + return getQueueDepthString((Long) attributes.get(columnIndex)); + } + else if(ATTR_MAX_QUEUE_DEPTH.equals(attrName) || ATTR_MAX_MSG_SIZE.equals(attrName)) + { + Number val = (Number)attributes.get(columnIndex); + return convertLongBytesToText(val.longValue()); + } + else if(ATTR_MAX_MSG_AGE.equals(attrName)) + { + return String.valueOf(attributes.get(columnIndex) + "ms"); + } + + return String.valueOf(attributes.get(columnIndex)); + } + } + + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + } + + @SuppressWarnings("unchecked") + @Override + protected void addMBeanToFavourites() + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex == -1) + { + return; + } + + int[] selectedIndices = _table.getSelectionIndices(); + + ArrayList<ManagedBean> selectedMBeans = new ArrayList<ManagedBean>(); + + boolean allSucceded = true; + //the entries are created from an List<Object> with the attribute values (name first) + for(int index = 0; index < selectedIndices.length ; index++) + { + List<Object> queueEntry = (List<Object>) _table.getItem(selectedIndices[index]).getData(); + String queueName = (String) queueEntry.get(0); + + ManagedBean queueMBean = _serverRegistry.getQueue(queueName, _virtualHost); + + //check queue had not already been unregistered before trying to add it + if(queueMBean != null) + { + selectedMBeans.add(queueMBean); + } + else + { + allSucceded = false; + } + } + + if(allSucceded) + { + //ensure the status bar is cleared of any previous failures added by the below + ViewUtility.clearStatusBar(); + } + else + { + ViewUtility.operationFailedStatusBarMessage("A selected queue could not be added as it was no longer registered"); + refresh(); + } + + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + NavigationView view = (NavigationView)window.getActivePage().findView(NavigationView.ID); + + ManagedBean bean = null; + try + { + for(ManagedBean mbean: selectedMBeans) + { + bean = mbean; + view.addManagedBean(mbean); + } + } + catch (Exception ex) + { + MBeanUtility.handleException(bean, ex); + } + } + + @SuppressWarnings("unchecked") + @Override + protected void openMBean() + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex == -1) + { + return; + } + + ManagedBean selectedMBean; + + //the entries are created from an List<Object> with the attribute values (name first) + List<Object> queueEntry = (List<Object>) _table.getItem(selectionIndex).getData(); + String queueName = (String) queueEntry.get(0); + selectedMBean = _serverRegistry.getQueue(queueName, _virtualHost); + + if(selectedMBean == null) + { + ViewUtility.popupErrorMessage("Error", "Unable to retrieve the selected MBean to open it"); + return; + } + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID); + try + { + view.openMBean(selectedMBean); + } + catch (Exception ex) + { + MBeanUtility.handleException(selectedMBean, ex); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/users/UserManagementTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/users/UserManagementTabControl.java new file mode 100644 index 0000000000..fdcc25d337 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/users/UserManagementTabControl.java @@ -0,0 +1,925 @@ +/* + * + * 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.users; + +import static org.apache.qpid.management.common.mbeans.UserManagement.RIGHTS_ADMIN; +import static org.apache.qpid.management.common.mbeans.UserManagement.RIGHTS_READ_ONLY; +import static org.apache.qpid.management.common.mbeans.UserManagement.RIGHTS_READ_WRITE; +import static org.apache.qpid.management.common.mbeans.UserManagement.USERNAME; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularDataSupport; + +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.common.mbeans.UserManagement; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.TabControl; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; + + +/** + * Control class for the UserManagement mbean. + */ +public class UserManagementTabControl extends TabControl +{ + private FormToolkit _toolkit; + private ScrolledForm _form; + private Table _table = null; + private TableViewer _tableViewer = null; + + private TabularDataSupport _userDetails = null; + private UserManagement _ummb; + private ApiVersion _ApiVersion; + + public UserManagementTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc) + { + super(tabFolder); + _mbean = mbean; + _ApiVersion = ApplicationRegistry.getServerRegistry(mbean).getManagementApiVersion(); + _ummb = (UserManagement) + MBeanServerInvocationHandler.newProxyInstance(mbsc, mbean.getObjectName(), + UserManagement.class, false); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createScrolledForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + createWidgets(); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + _table.setFocus(); + } + + @Override + public void refresh(ManagedBean mbean) + { + _userDetails = null; + try + { + _userDetails = (TabularDataSupport) _ummb.viewUsers(); + } + catch(Exception e) + { + MBeanUtility.handleException(_mbean, e); + + } + + _tableViewer.setInput(_userDetails); + + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + private void createWidgets() + { + Composite paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + paramsComposite.setLayout(new GridLayout()); + + Group viewUsersGroup = new Group(paramsComposite, SWT.SHADOW_NONE); + viewUsersGroup.setBackground(paramsComposite.getBackground()); + viewUsersGroup.setText("Users"); + viewUsersGroup.setLayout(new GridLayout(2,false)); + viewUsersGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + Composite tableComposite = _toolkit.createComposite(viewUsersGroup); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.heightHint = 250; + gridData.minimumHeight = 250; + tableComposite.setLayoutData(gridData); + tableComposite.setLayout(new GridLayout(2,false)); + + _table = new Table (tableComposite, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _table.setLinesVisible (true); + _table.setHeaderVisible (true); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + _table.setLayoutData(gridData); + + _tableViewer = new TableViewer(_table); + final TableSorter tableSorter = new TableSorter(); + + String[] titles = { "Username", "JMX Management Rights" }; + int[] bounds = { 310, 200 }; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableViewerColumn viewerColumn = new TableViewerColumn(_tableViewer, SWT.NONE); + final TableColumn column = viewerColumn.getColumn(); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _tableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _tableViewer.setContentProvider(new ContentProviderImpl()); + _tableViewer.setLabelProvider(new LabelProviderImpl()); + _tableViewer.setSorter(tableSorter); + _table.setSortColumn(_table.getColumn(0)); + _table.setSortDirection(SWT.UP); + + Composite buttonsComposite = _toolkit.createComposite(tableComposite); + gridData = new GridData(SWT.FILL, SWT.TOP, false, false); + gridData.heightHint = 165; + buttonsComposite.setLayoutData(gridData); + buttonsComposite.setLayout(new GridLayout()); + + final Button addUserButton = _toolkit.createButton(buttonsComposite, "Add New User ...", SWT.PUSH); + gridData = new GridData(SWT.CENTER, SWT.TOP, false, true); + gridData.widthHint = 125; + addUserButton.setLayoutData(gridData); + addUserButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + addUser(addUserButton.getShell()); + } + }); + + final Button deleteUsersButton = _toolkit.createButton(buttonsComposite, "Delete User(s)", SWT.PUSH); + gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false); + gridData.widthHint = 125; + deleteUsersButton.setLayoutData(gridData); + deleteUsersButton.setEnabled(false); + deleteUsersButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + deleteUsers(); + } + } + }); + + final Button setPasswordButton = _toolkit.createButton(buttonsComposite, "Set Password ...", SWT.PUSH); + gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false); + gridData.widthHint = 125; + setPasswordButton.setLayoutData(gridData); + setPasswordButton.setEnabled(false); + setPasswordButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + final CompositeData selectedLogger = (CompositeData)_table.getItem( + selectionIndex).getData(); + String user = selectedLogger.get(USERNAME).toString(); + InputDialog id = new InputDialog(setPasswordButton.getShell(),"Set Password", + "Please enter the new password for '" + user + "':",null,null){ + @Override + protected Control createDialogArea(Composite parent) + { + Control control = super.createDialogArea(parent); + //set the Text field echo char to '*' to mask the password + getText().setEchoChar('*'); + //return the normal result + return control; + } + }; + + int returnValue; + while((returnValue = id.open()) == InputDialog.OK) + { + if (id.getValue() == null || id.getValue().toString().length() == 0) + { + ViewUtility.popupErrorMessage("Set Password", "Please enter a valid password"); + } + else + { + break; + } + } + + if (returnValue == InputDialog.OK) + { + char[] password = id.getValue().toCharArray(); + + // Qpid JMX API 1.1 and below expects the password to be sent as a hashed value. + if (_ApiVersion.lessThanOrEqualTo(1,1)) + { + try + { + password = ViewUtility.getHash(id.getValue()); + } + catch (Exception hashException) + { + ViewUtility.popupErrorMessage("Set Password", + "Unable to calculate hash for Password:" + + hashException.getMessage()); + return; + } + } + + try + { + boolean result = _ummb.setPassword(user, password); + ViewUtility.operationResultFeedback(result, "Updated user password", "Failed to update user password"); + } + catch(Exception e2) + { + ViewUtility.operationFailedStatusBarMessage("Error updating user password"); + MBeanUtility.handleException(_mbean, e2); + } + } + } + } + }); + + final Button setRightsButton = _toolkit.createButton(buttonsComposite, "Set Rights ...", SWT.PUSH); + gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false); + gridData.widthHint = 125; + setRightsButton.setLayoutData(gridData); + setRightsButton.setEnabled(false); + setRightsButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex != -1) + { + setRights(setRightsButton.getShell()); + } + } + }); + + _tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex == -1) + { + deleteUsersButton.setEnabled(false); + setRightsButton.setEnabled(false); + setPasswordButton.setEnabled(false); + return; + } + else + { + deleteUsersButton.setEnabled(true); + setRightsButton.setEnabled(true); + } + + if (_table.getSelectionCount() > 1) + { + setPasswordButton.setEnabled(false); + } + else + { + setPasswordButton.setEnabled(true); + } + } + }); + + Group miscGroup = new Group(paramsComposite, SWT.SHADOW_NONE); + miscGroup.setBackground(paramsComposite.getBackground()); + miscGroup.setText("Misc"); + gridData = new GridData(SWT.LEFT, SWT.TOP, true, true); + miscGroup.setLayoutData(gridData); + miscGroup.setLayout(new GridLayout(2,false)); + + final Button reloadUserDetails = _toolkit.createButton(miscGroup, + "Reload User Details", SWT.PUSH); + if(_ApiVersion.lessThan(1, 2)) + { + //this only reloaded the JMX rights file before Qpid JMX API 1.2 + _toolkit.createLabel(miscGroup, " Loads the current management rights file from disk"); + } + else + { + //since Qpid JMX API 1.2 it also reloads the password file + _toolkit.createLabel(miscGroup, " Loads the current password and management rights files from disk"); + } + reloadUserDetails.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + int response = ViewUtility.popupOkCancelConfirmationMessage("Reload User Data", + "Do you want to reload user data ?"); + if (response == SWT.OK) + { + try + { + boolean result = _ummb.reloadData(); + ViewUtility.operationResultFeedback(result, "Reloaded user data", "Failed to reload user data"); + } + catch(Exception e3) + { + ViewUtility.operationFailedStatusBarMessage("Error reloading user data"); + MBeanUtility.handleException(_mbean, e3); + } + refresh(_mbean); + } + } + }); + + } + + + /** + * Content Provider class for the table viewer + */ + private static class ContentProviderImpl implements IStructuredContentProvider + { + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + public Object[] getElements(Object parent) + { + Collection<Object> rowCollection = ((TabularDataSupport) parent).values(); + + return rowCollection.toArray(); + } + } + + /** + * Label Provider class for the table viewer + */ + private class LabelProviderImpl extends LabelProvider implements ITableLabelProvider + { + @Override + public String getColumnText(Object element, int columnIndex) + { + switch (columnIndex) + { + case 0 : // username column + return (String) ((CompositeData) element).get(USERNAME); + case 1 : // rights column + return classifyUserRights((CompositeData) element); + default : + return "-"; + } + } + + @Override + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + } + + /** + * Sorter class for the table viewer. + * + */ + private class TableSorter extends ViewerSorter + { + private int column; + private static final int ASCENDING = 0; + private static final int DESCENDING = 1; + + private int direction; + + public TableSorter() + { + this.column = 0; + direction = ASCENDING; + } + + public void setColumn(int column) + { + if(column == this.column) + { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } + else + { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + CompositeData user1 = (CompositeData) e1; + CompositeData user2 = (CompositeData) e2; + + int comparison = 0; + switch(column) + { + case 0: + comparison = String.valueOf(user1.get(USERNAME)).compareTo( + String.valueOf(user2.get(USERNAME))); + break; + case 1: + comparison = classifyUserRights(user1).compareTo(classifyUserRights(user2)); + break; + default: + comparison = 0; + } + // If descending order, flip the direction + if(direction == DESCENDING) + { + comparison = -comparison; + } + return comparison; + } + } + + private String classifyUserRights(CompositeData user) + { + Boolean read = (Boolean)user.get(RIGHTS_READ_ONLY); + Boolean write = (Boolean)user.get(RIGHTS_READ_WRITE); + Boolean admin = (Boolean)user.get(RIGHTS_ADMIN); + + if(admin) + { + return "Admin"; + } + else if(write) + { + return "Read & Write"; + } + else if(read) + { + return "Read Only"; + } + else + { + return "No Access"; + } + } + + private void setRights(final Shell parent) + { + + int selectionIndex = _table.getSelectionIndex(); + + if (selectionIndex == -1) + { + return; + } + + int[] selectedIndices = _table.getSelectionIndices(); + + final ArrayList<String> selectedUsers = new ArrayList<String>(); + + for(int index = 0; index < selectedIndices.length ; index++) + { + CompositeData selectedUser = (CompositeData)_table.getItem(selectedIndices[index]).getData(); + String user = selectedUser.get(USERNAME).toString(); + selectedUsers.add(user); + } + + String selectedUsersString = ""; + for(String user : selectedUsers) + { + selectedUsersString = selectedUsersString.concat(user + ", "); + } + //cut off last ", " + int lastIndex = selectedUsersString.lastIndexOf(','); + if (lastIndex != -1) + { + selectedUsersString = selectedUsersString.substring(0,lastIndex); + } + + + + final Shell shell = ViewUtility.createModalDialogShell(parent, "Set Rights"); + + Label overview = _toolkit.createLabel(shell,"Select rights for user(s): "); + overview.setBackground(shell.getBackground()); + Label userNamesLabel= _toolkit.createLabel(shell,selectedUsersString); + userNamesLabel.setBackground(shell.getBackground()); + + Composite buttons = _toolkit.createComposite(shell, SWT.NONE); + buttons.setBackground(shell.getBackground()); + buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + buttons.setLayout(new GridLayout(4,false)); + + final Button noneButton = new Button(buttons, SWT.RADIO); + noneButton.setText("No Access"); + noneButton.setSelection(true); + final Button readButton = new Button(buttons, SWT.RADIO); + readButton.setText("Read Only"); + final Button writeButton = new Button(buttons, SWT.RADIO); + writeButton.setText("Read + Write"); + final Button adminButton = new Button(buttons, SWT.RADIO); + adminButton.setText("Admin"); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + boolean read = readButton.getSelection(); + boolean write = writeButton.getSelection(); + boolean admin = adminButton.getSelection(); + + shell.dispose(); + + HashMap<String,Boolean> results = new HashMap<String,Boolean>(); + try + { + //perform the rights updates, save the results. + for(String user : selectedUsers) + { + boolean result = _ummb.setRights(user,read,write,admin); + results.put(user, result); + } + + //categorise the overall result + boolean overallResult = true; + for(boolean result : results.values()) + { + if (!result) + { + overallResult = false; + } + } + + //output the result to status bar if all success, and dialogue if not + if(overallResult) + { + ViewUtility.operationResultFeedback(overallResult, "Updated user rights", null); + } + else + { + String failedToUpdateRightsUsers = ""; + for(String user : results.keySet()) + { + if(!results.get(user)) + { + failedToUpdateRightsUsers = failedToUpdateRightsUsers.concat(user + ", "); + } + } + + //cut off last ", " + int lastIndex2 = failedToUpdateRightsUsers.lastIndexOf(','); + if (lastIndex2 != -1) + { + failedToUpdateRightsUsers = failedToUpdateRightsUsers.substring(0, lastIndex2); + } + + ViewUtility.operationResultFeedback(overallResult, null, "Failed to update user(s) rights: " + failedToUpdateRightsUsers); + } + } + catch(Exception e4) + { + ViewUtility.operationFailedStatusBarMessage("Error updating user rights"); + MBeanUtility.handleException(_mbean, e4); + } + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private void addUser(final Shell parent) + { + final Shell shell = ViewUtility.createModalDialogShell(parent, "Add New User"); + + Composite usernameComposite = _toolkit.createComposite(shell, SWT.NONE); + usernameComposite.setBackground(shell.getBackground()); + usernameComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + usernameComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(usernameComposite,"Username:").setBackground(shell.getBackground()); + final Text usernameText = new Text(usernameComposite, SWT.BORDER); + usernameText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Composite passwordComposite = _toolkit.createComposite(shell, SWT.NONE); + passwordComposite.setBackground(shell.getBackground()); + passwordComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + passwordComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(passwordComposite,"Password:").setBackground(shell.getBackground()); + final Text passwordText = new Text(passwordComposite, SWT.BORDER | SWT.PASSWORD); + passwordText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Group buttonGroup = new Group(shell, SWT.NONE); + buttonGroup.setText("JMX Management Rights"); + buttonGroup.setBackground(shell.getBackground()); + buttonGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + buttonGroup.setLayout(new GridLayout(4,false)); + + final Button noneButton = new Button(buttonGroup, SWT.RADIO); + noneButton.setText("No Access"); + noneButton.setSelection(true); + final Button readButton = new Button(buttonGroup, SWT.RADIO); + readButton.setText("Read Only"); + final Button writeButton = new Button(buttonGroup, SWT.RADIO); + writeButton.setText("Read + Write"); + final Button adminButton = new Button(buttonGroup, SWT.RADIO); + adminButton.setText("Admin"); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String username = usernameText.getText(); + String password = passwordText.getText(); + + if (username == null || username.length() == 0) + { + ViewUtility.popupErrorMessage("Add New User", "Please enter a valid username"); + return; + } + + if (password == null || password.length() == 0) + { + ViewUtility.popupErrorMessage("Add New User", "Please enter a valid password"); + return; + } + + char[] passwordChars = password.toCharArray(); + + // Qpid JMX API 1.1 and below expects the password to be sent as a hashed value. + if (_ApiVersion.lessThanOrEqualTo(1,1)) + { + try + { + passwordChars = ViewUtility.getHash(password); + } + catch (Exception hashException) + { + ViewUtility.popupErrorMessage("Set Password", + "Unable to calculate hash for Password:" + + hashException.getMessage()); + return; + } + } + + boolean read = readButton.getSelection(); + boolean write = writeButton.getSelection(); + boolean admin = adminButton.getSelection(); + + shell.dispose(); + try + { + boolean result = false; + // If we have Qpid JMX API 1.7 or above, use newer createUser method with String based password. + if (_ApiVersion.greaterThanOrEqualTo(1,7)) + { + result = _ummb.createUser(username, password, read, write, admin); + } + else + { + result = _ummb.createUser(username, passwordChars, read, write, admin); + } + + ViewUtility.operationResultFeedback(result, "Created user", "Failed to create user"); + } + catch(Exception e5) + { + ViewUtility.operationFailedStatusBarMessage("Error creating user"); + MBeanUtility.handleException(_mbean, e5); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private void deleteUsers() + { + int selectionIndex = _table.getSelectionIndex(); + if (selectionIndex == -1) + { + return; + } + + int[] selectedIndices = _table.getSelectionIndices(); + + ArrayList<String> selectedUsers = new ArrayList<String>(); + + for(int index = 0; index < selectedIndices.length ; index++) + { + CompositeData selectedUser = (CompositeData)_table.getItem(selectedIndices[index]).getData(); + String user = selectedUser.get(USERNAME).toString(); + selectedUsers.add(user); + } + + String selectedUsersString = ""; + for(String user : selectedUsers) + { + selectedUsersString = selectedUsersString.concat(user + ", "); + } + //cut off last ", " + int lastIndex = selectedUsersString.lastIndexOf(','); + if (lastIndex != -1) + { + selectedUsersString = selectedUsersString.substring(0,lastIndex); + } + + int response = ViewUtility.popupOkCancelConfirmationMessage( + "User Management", "Delete user(s): " + selectedUsersString + " ?"); + + if (response == SWT.OK) + { + HashMap<String,Boolean> results = new HashMap<String,Boolean>(); + try + { + //perform the deletes, save the results. + for(String user : selectedUsers) + { + boolean result = _ummb.deleteUser(user); + results.put(user, result); + } + + //categorise the overall result + boolean overallResult = true; + for(boolean result : results.values()) + { + if (!result) + { + overallResult = false; + } + } + + //output the result to status bar if all success, and dialogue if not + if(overallResult) + { + ViewUtility.operationResultFeedback(overallResult, "Deleted user(s)", null); + } + else + { + String failedToDeleteUsers = ""; + for(String user : results.keySet()) + { + if(!results.get(user)) + { + failedToDeleteUsers = failedToDeleteUsers.concat(user + ", "); + } + } + + //cut off last ", " + lastIndex = failedToDeleteUsers.lastIndexOf(','); + if (lastIndex != -1) + { + failedToDeleteUsers = failedToDeleteUsers.substring(0, lastIndex); + } + + ViewUtility.operationResultFeedback(overallResult, null, "Failed to delete user(s): " + failedToDeleteUsers); + } + + } + catch(Exception e1) + { + ViewUtility.operationFailedStatusBarMessage("Error deleting user(s)"); + MBeanUtility.handleException(_mbean, e1); + } + + refresh(_mbean);; + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/vhost/VHostTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/vhost/VHostTabControl.java new file mode 100644 index 0000000000..0cbb1389d8 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/vhost/VHostTabControl.java @@ -0,0 +1,871 @@ +/* + * + * 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.vhost; + +import static org.apache.qpid.management.ui.Constants.DEFAULT_EXCHANGE_TYPE_VALUES; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; + +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.ServerRegistry; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.ui.jmx.JMXManagedObject; +import org.apache.qpid.management.ui.jmx.MBeanUtility; +import org.apache.qpid.management.ui.views.MBeanView; +import org.apache.qpid.management.ui.views.TabControl; +import org.apache.qpid.management.ui.views.ViewUtility; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.widgets.Form; +import org.eclipse.ui.forms.widgets.FormToolkit; + + +/** + * Control class for the VirtualHostManager mbean operations tab. + */ +public class VHostTabControl extends TabControl +{ + private FormToolkit _toolkit; + private Form _form; + private Table _queueTable = null; + private TableViewer _queueTableViewer = null; + private Table _exchangeTable = null; + private TableViewer _exchangeTableViewer = null; + + private Composite _paramsComposite = null; + + private ManagedBroker _vhmb; + private ApiVersion _ApiVersion; + private List<ManagedBean> _queues; + private List<ManagedBean> _exchanges; + private ServerRegistry _serverRegistry; + + public VHostTabControl(TabFolder tabFolder, JMXManagedObject mbean, MBeanServerConnection mbsc) + { + super(tabFolder); + _mbean = mbean; + _serverRegistry = ApplicationRegistry.getServerRegistry(mbean); + _ApiVersion = _serverRegistry.getManagementApiVersion(); + _vhmb = (ManagedBroker) MBeanServerInvocationHandler.newProxyInstance(mbsc, + mbean.getObjectName(), ManagedBroker.class, false); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createForm(_tabFolder); + _form.getBody().setLayout(new GridLayout()); + createComposites(); + createWidgets(); + } + + private void createComposites() + { + _paramsComposite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + _paramsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + _paramsComposite.setLayout(new GridLayout(2, true)); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + return _form; + } + + /** + * @see TabControl#setFocus() + */ + public void setFocus() + { + + } + + @Override + public void refresh(ManagedBean mbean) + { + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer()); + _queues = serverRegistry.getQueues(MBeanView.getVirtualHost()); + _exchanges = serverRegistry.getExchanges(MBeanView.getVirtualHost()); + + _queueTableViewer.setInput(_queues); + _exchangeTableViewer.setInput(_exchanges); + + layout(); + } + + public void layout() + { + _form.layout(true); + _form.getBody().layout(true, true); + } + + private void createWidgets() + { + Group queuesGroup = new Group(_paramsComposite, SWT.SHADOW_NONE); + queuesGroup.setBackground(_paramsComposite.getBackground()); + queuesGroup.setText("Queues"); + queuesGroup.setLayout(new GridLayout(2,false)); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + queuesGroup.setLayoutData(gridData); + + _queueTable = new Table (queuesGroup, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _queueTable.setLinesVisible (true); + _queueTable.setHeaderVisible (true); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + _queueTable.setLayoutData(data); + + _queueTableViewer = new TableViewer(_queueTable); + final TableSorter tableSorter = new TableSorter(); + + String[] titles = {"Name"}; + int[] bounds = { 250 }; + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableColumn column = new TableColumn (_queueTable, SWT.NONE); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + tableSorter.setColumn(index); + final TableViewer viewer = _queueTableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _queueTableViewer.setContentProvider(new ContentProviderImpl()); + _queueTableViewer.setLabelProvider(new LabelProviderImpl()); + _queueTableViewer.setSorter(tableSorter); + _queueTable.setSortColumn(_queueTable.getColumn(0)); + _queueTable.setSortDirection(SWT.UP); + + Composite queuesRightComposite = _toolkit.createComposite(queuesGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + queuesRightComposite.setLayoutData(gridData); + queuesRightComposite.setLayout(new GridLayout()); + + final Button createQueueButton = _toolkit.createButton(queuesRightComposite, "Create ...", SWT.PUSH); + createQueueButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); + createQueueButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + createQueue(createQueueButton.getShell()); + } + }); + + final Button deleteQueueButton = _toolkit.createButton(queuesRightComposite, "Delete", SWT.PUSH); + deleteQueueButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + deleteQueueButton.setEnabled(false); + deleteQueueButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + deleteQueuesOrExchanges(deleteQueueButton.getShell(), VhostOperations.DELETE_QUEUE); + } + }); + + _queueTableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _queueTable.getSelectionIndex(); + + if (selectionIndex != -1) + { + deleteQueueButton.setEnabled(true); + } + else + { + deleteQueueButton.setEnabled(false); + } + } + }); + + //listener for double clicking to open the selection mbean + _queueTable.addMouseListener(new MouseListener() + { + // MouseListener implementation + public void mouseDoubleClick(MouseEvent event) + { + openMBean(_queueTable); + } + + public void mouseDown(MouseEvent e){} + public void mouseUp(MouseEvent e){} + }); + + Group exchangesGroup = new Group(_paramsComposite, SWT.SHADOW_NONE); + exchangesGroup.setBackground(_paramsComposite.getBackground()); + exchangesGroup.setText("Exchanges"); + exchangesGroup.setLayout(new GridLayout(2,false)); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + exchangesGroup.setLayoutData(gridData); + + _exchangeTable = new Table (exchangesGroup, SWT.MULTI | SWT.SCROLL_LINE | SWT.BORDER | SWT.FULL_SELECTION); + _exchangeTable.setLinesVisible (true); + _exchangeTable.setHeaderVisible (true); + data = new GridData(SWT.FILL, SWT.FILL, true, true); + _exchangeTable.setLayoutData(data); + + _exchangeTableViewer = new TableViewer(_exchangeTable); + final TableSorter exchangeTableSorter = new TableSorter(); + + for (int i = 0; i < titles.length; i++) + { + final int index = i; + final TableColumn column = new TableColumn (_exchangeTable, SWT.NONE); + + column.setText(titles[i]); + column.setWidth(bounds[i]); + column.setResizable(true); + + //Setting the right sorter + column.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + exchangeTableSorter.setColumn(index); + final TableViewer viewer = _exchangeTableViewer; + int dir = viewer .getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) + { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } + else + { + dir = SWT.UP; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }); + + } + + _exchangeTableViewer.setContentProvider(new ContentProviderImpl()); + _exchangeTableViewer.setLabelProvider(new LabelProviderImpl()); + _exchangeTableViewer.setSorter(exchangeTableSorter); + _exchangeTable.setSortColumn(_exchangeTable.getColumn(0)); + _exchangeTable.setSortDirection(SWT.UP); + + Composite exchangesRightComposite = _toolkit.createComposite(exchangesGroup); + gridData = new GridData(SWT.FILL, SWT.FILL, false, true); + exchangesRightComposite.setLayoutData(gridData); + exchangesRightComposite.setLayout(new GridLayout()); + + final Button createExchangeButton = _toolkit.createButton(exchangesRightComposite, "Create ...", SWT.PUSH); + createExchangeButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); + createExchangeButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + createExchange(createQueueButton.getShell()); + } + }); + + final Button deleteExchangeButton = _toolkit.createButton(exchangesRightComposite, "Delete", SWT.PUSH); + deleteExchangeButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + deleteExchangeButton.setEnabled(false); + deleteExchangeButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + deleteQueuesOrExchanges(deleteExchangeButton.getShell(), VhostOperations.DELETE_EXCHANGE); + } + }); + + _exchangeTableViewer.addSelectionChangedListener(new ISelectionChangedListener(){ + public void selectionChanged(SelectionChangedEvent evt) + { + int selectionIndex = _exchangeTable.getSelectionIndex(); + + if (selectionIndex != -1) + { + deleteExchangeButton.setEnabled(true); + } + else + { + deleteExchangeButton.setEnabled(false); + } + } + }); + + //listener for double clicking to open the selection mbean + _exchangeTable.addMouseListener(new MouseListener() + { + // MouseListener implementation + public void mouseDoubleClick(MouseEvent event) + { + openMBean(_exchangeTable); + } + + public void mouseDown(MouseEvent e){} + public void mouseUp(MouseEvent e){} + }); + } + + + /** + * Content Provider class for the table viewer + */ + private static class ContentProviderImpl implements IStructuredContentProvider + { + + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + + public void dispose() + { + + } + + @SuppressWarnings("unchecked") + public Object[] getElements(Object parent) + { + return ((List<ManagedBean>) parent).toArray(); + } + } + + /** + * Label Provider class for the table viewer + */ + private static class LabelProviderImpl extends LabelProvider implements ITableLabelProvider + { + @Override + public String getColumnText(Object element, int columnIndex) + { + switch (columnIndex) + { + case 0 : // name column + return ((ManagedBean) element).getName(); + default : + return "-"; + } + } + + @Override + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + } + + /** + * Sorter class for the table viewer. + * + */ + public static class TableSorter extends ViewerSorter + { + private int column; + private static final int ASCENDING = 0; + private static final int DESCENDING = 1; + + private int direction = DESCENDING; + + public TableSorter() + { + this.column = 0; + direction = ASCENDING; + } + + public void setColumn(int column) + { + if (column == this.column) + { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } + else + { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) + { + ManagedBean mbean1 = (ManagedBean ) e1; + ManagedBean mbean2 = (ManagedBean ) e2; + + int comparison = 0; + switch(column) + { + case 0: + comparison = mbean1.getName().compareTo(mbean2.getName()); + break; + default: + comparison = 0; + } + // If descending order, flip the direction + if(direction == DESCENDING) + { + comparison = -comparison; + } + return comparison; + } + } + + private void createQueue(final Shell parent) + { + final Shell shell = ViewUtility.createModalDialogShell(parent, "Create Queue"); + + Composite nameComposite = _toolkit.createComposite(shell, SWT.NONE); + nameComposite.setBackground(shell.getBackground()); + nameComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + nameComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(nameComposite,"Name:").setBackground(shell.getBackground()); + final Text nameText = new Text(nameComposite, SWT.BORDER); + nameText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Composite ownerComposite = _toolkit.createComposite(shell, SWT.NONE); + ownerComposite.setBackground(shell.getBackground()); + ownerComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + ownerComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(ownerComposite,"Owner (optional):").setBackground(shell.getBackground()); + final Text ownerText = new Text(ownerComposite, SWT.BORDER); + ownerText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Composite durableComposite = _toolkit.createComposite(shell, SWT.NONE); + durableComposite.setBackground(shell.getBackground()); + GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); + gridData.minimumWidth = 220; + durableComposite.setLayoutData(gridData); + durableComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(durableComposite,"Durable:").setBackground(shell.getBackground()); + final Button durableButton = new Button(durableComposite, SWT.CHECK); + durableButton.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false)); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String name = nameText.getText(); + + if (name == null || name.length() == 0) + { + ViewUtility.popupErrorMessage("Create Queue", "Please enter a valid name"); + return; + } + + String owner = ownerText.getText(); + + if (owner != null && owner.length() == 0) + { + owner = null; + } + + boolean durable = durableButton.getSelection(); + + shell.dispose(); + + try + { + _vhmb.createNewQueue(name, owner, durable); + + ViewUtility.operationResultFeedback(null, "Created Queue", null); + try + { + //delay to allow mbean registration notification processing + Thread.sleep(250); + } + catch(InterruptedException ie) + { + //ignore + } + } + catch(Exception e5) + { + ViewUtility.operationFailedStatusBarMessage("Error creating Queue"); + MBeanUtility.handleException(_mbean, e5); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private void createExchange(final Shell parent) + { + final Shell shell = ViewUtility.createModalDialogShell(parent, "Create Exchange"); + + Composite nameComposite = _toolkit.createComposite(shell, SWT.NONE); + nameComposite.setBackground(shell.getBackground()); + nameComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + nameComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(nameComposite,"Name:").setBackground(shell.getBackground()); + final Text nameText = new Text(nameComposite, SWT.BORDER); + nameText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Composite typeComposite = _toolkit.createComposite(shell, SWT.NONE); + typeComposite.setBackground(shell.getBackground()); + typeComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + typeComposite.setLayout(new GridLayout(2,false)); + + String[] exchangeTypes; + if(_ApiVersion.greaterThanOrEqualTo(1, 3))//if the server supports Qpid JMX API 1.3 + {//request the current exchange types from the broker + try + { + exchangeTypes = _vhmb.getExchangeTypes(); + } + catch (IOException e1) + { + exchangeTypes = DEFAULT_EXCHANGE_TYPE_VALUES.toArray(new String[DEFAULT_EXCHANGE_TYPE_VALUES.size()]); + } + } + else //use the fallback defaults. + { + exchangeTypes = DEFAULT_EXCHANGE_TYPE_VALUES.toArray(new String[DEFAULT_EXCHANGE_TYPE_VALUES.size()]); + } + + _toolkit.createLabel(typeComposite,"Type:").setBackground(shell.getBackground()); + final org.eclipse.swt.widgets.List typeList = new org.eclipse.swt.widgets.List(typeComposite, SWT.SINGLE | SWT.BORDER); + typeList.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + typeList.setItems(exchangeTypes); + + Composite durableComposite = _toolkit.createComposite(shell, SWT.NONE); + durableComposite.setBackground(shell.getBackground()); + GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); + gridData.minimumWidth = 220; + durableComposite.setLayoutData(gridData); + durableComposite.setLayout(new GridLayout(2,false)); + + _toolkit.createLabel(durableComposite,"Durable:").setBackground(shell.getBackground()); + final Button durableButton = new Button(durableComposite, SWT.CHECK); + durableButton.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false)); + + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + String name = nameText.getText(); + + if (name == null || name.length() == 0) + { + ViewUtility.popupErrorMessage("Create Exchange", "Please enter a valid name"); + return; + } + + int selectedTypeIndex = typeList.getSelectionIndex(); + + if (selectedTypeIndex == -1) + { + ViewUtility.popupErrorMessage("Create Exchange", "Please select an Exchange type"); + return; + } + + String type = typeList.getItem(selectedTypeIndex); + + boolean durable = durableButton.getSelection(); + + shell.dispose(); + + try + { + _vhmb.createNewExchange(name, type, durable); + + ViewUtility.operationResultFeedback(null, "Created Exchange", null); + try + { + //delay to allow mbean registration notification processing + Thread.sleep(250); + } + catch(InterruptedException ie) + { + //ignore + } + } + catch(Exception e5) + { + ViewUtility.operationFailedStatusBarMessage("Error creating Exchange"); + MBeanUtility.handleException(_mbean, e5); + } + + refresh(_mbean); + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private void deleteQueuesOrExchanges(Shell parent, final VhostOperations op) + { + Table table; + String windowTitle; + String dialogueMessage; + final String feedBackMessage; + final String failureFeedBackMessage; + + if(op.equals(VhostOperations.DELETE_QUEUE)) + { + table = _queueTable; + windowTitle = "Delete Queue(s)"; + dialogueMessage = "Delete Queue(s): "; + feedBackMessage = "Queue(s) deleted"; + failureFeedBackMessage = "Error deleting Queue(s)"; + } + else + { + table = _exchangeTable; + windowTitle = "Delete Exchange(s)"; + dialogueMessage = "Delete Exchange(s): "; + feedBackMessage = "Exchange(s) deleted"; + failureFeedBackMessage = "Error deleting Exchange(s)"; + } + + int selectionIndex = table.getSelectionIndex(); + if (selectionIndex == -1) + { + return; + } + + int[] selectedIndices = table.getSelectionIndices(); + + final ArrayList<ManagedBean> selectedMBeans = new ArrayList<ManagedBean>(); + + for(int index = 0; index < selectedIndices.length ; index++) + { + ManagedBean selectedMBean = (ManagedBean)table.getItem(selectedIndices[index]).getData(); + selectedMBeans.add(selectedMBean); + } + + + final Shell shell = ViewUtility.createModalDialogShell(parent, windowTitle); + + _toolkit.createLabel(shell, dialogueMessage).setBackground(shell.getBackground()); + + final Text headerText = new Text(shell, SWT.WRAP | SWT.V_SCROLL | SWT.BORDER ); + headerText.setEditable(false); + GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); + data.minimumHeight = 150; + data.heightHint = 150; + data.minimumWidth = 400; + data.widthHint = 400; + headerText.setLayoutData(data); + + String lineSeperator = System.getProperty("line.separator"); + for(ManagedBean mbean : selectedMBeans) + { + headerText.append(mbean.getName() + lineSeperator); + } + headerText.setSelection(0); + + Composite okCancelButtonsComp = _toolkit.createComposite(shell); + okCancelButtonsComp.setBackground(shell.getBackground()); + okCancelButtonsComp.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); + okCancelButtonsComp.setLayout(new GridLayout(2,false)); + + Button okButton = _toolkit.createButton(okCancelButtonsComp, "OK", SWT.PUSH); + okButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + Button cancelButton = _toolkit.createButton(okCancelButtonsComp, "Cancel", SWT.PUSH); + cancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false)); + + okButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + + try + { + //perform the deletes + for(ManagedBean mbean : selectedMBeans) + { + switch(op) + { + case DELETE_QUEUE: + _vhmb.deleteQueue(mbean.getName()); + _serverRegistry.removeManagedObject(mbean); + break; + case DELETE_EXCHANGE: + _vhmb.unregisterExchange(mbean.getName()); + break; + } + //remove the mbean from the server registry now instead of + //waiting for an mbean Unregistration Notification to do it + _serverRegistry.removeManagedObject(mbean); + } + + ViewUtility.operationResultFeedback(null, feedBackMessage, null); + } + catch(Exception e1) + { + ViewUtility.operationFailedStatusBarMessage(failureFeedBackMessage); + MBeanUtility.handleException(_mbean, e1); + } + + refresh(_mbean);; + } + }); + + cancelButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + shell.dispose(); + } + }); + + shell.setDefaultButton(okButton); + shell.pack(); + ViewUtility.centerChildInParentShell(parent, shell); + + shell.open(); + } + + private enum VhostOperations + { + DELETE_QUEUE, + DELETE_EXCHANGE; + } + + private void openMBean(Table table) + { + int selectionIndex = table.getSelectionIndex(); + + if (selectionIndex == -1) + { + return; + } + + ManagedBean selectedMBean = (ManagedBean) table.getItem(selectionIndex).getData(); + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + MBeanView view = (MBeanView) window.getActivePage().findView(MBeanView.ID); + try + { + view.openMBean(selectedMBean); + } + catch (Exception ex) + { + MBeanUtility.handleException(selectedMBean, ex); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/.eclipseproduct b/qpid/java/management/eclipse-plugin/src/main/resources/.eclipseproduct new file mode 100644 index 0000000000..28ee27ca17 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/.eclipseproduct @@ -0,0 +1,23 @@ +#Eclipse Product File
+#Fri Nov 03 14:47:54 GMT 2006
+#
+# 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.
+#
+version=1.0-incubating-M2-SNAPSHOT
+name=Qpid Management Console
+id=org.apache.qpid.manager.gui.product
diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/jmxremote.sasl-plugin/MANIFEST.MF b/qpid/java/management/eclipse-plugin/src/main/resources/jmxremote.sasl-plugin/MANIFEST.MF new file mode 100644 index 0000000000..83c7c9f435 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/jmxremote.sasl-plugin/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt +Bundle-ManifestVersion: 2 +Bundle-Name: jmx sasl Plug-in +Bundle-SymbolicName: jmxremote.sasl +Bundle-Version: 1.0.1 +Bundle-ClassPath: jmxremote_optional.jar +Export-Package: com.sun.jmx.remote.generic, + com.sun.jmx.remote.opt.internal, + com.sun.jmx.remote.opt.security, + com.sun.jmx.remote.opt.util, + com.sun.jmx.remote.profile.sasl, + com.sun.jmx.remote.profile.tls, + com.sun.jmx.remote.protocol.jmxmp, + com.sun.jmx.remote.socket, + javax.management.remote.generic, + javax.management.remote.jmxmp, + javax.management.remote.message +Bundle-Vendor: +Bundle-Localization: plugin diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/Configuration/config.ini b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/Configuration/config.ini new file mode 100644 index 0000000000..dc15366740 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/Configuration/config.ini @@ -0,0 +1,49 @@ +###############################################################################
+# 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.
+###############################################################################
+
+#Product Runtime Configuration File + +osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui +eclipse.product=org.apache.qpid.management.ui.product +osgi.bundles.defaultStartLevel=4 +osgi.bundles=jmxremote.sasl, \ +qpid-management-common, \ +org.apache.qpid.management.ui, \ +com.ibm.icu, \ +org.eclipse.core.commands, \ +org.eclipse.core.contenttype, \ +org.eclipse.core.databinding, \ +org.eclipse.core.expressions, \ +org.eclipse.core.jobs, \ +org.eclipse.core.runtime@start, \ +org.eclipse.core.runtime.compatibility.registry, \ +org.eclipse.equinox.app,org.eclipse.equinox.common, \ +org.eclipse.equinox.preferences, \ +org.eclipse.equinox.registry, \ +org.eclipse.help, \ +org.eclipse.jface, \ +org.eclipse.jface.databinding, \ +org.eclipse.swt, \ +org.eclipse.swt.gtk.linux.x86, \ +org.eclipse.ui, \ +org.eclipse.ui.forms, \ +org.eclipse.ui.workbench, \ +org.eclipse.equinox.launcher, \ +org.eclipse.equinox.launcher.gtk.linux.x86, \ +org.apache.commons.codec diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/libcairo-swt.so b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/libcairo-swt.so Binary files differnew file mode 100644 index 0000000000..b66f95814e --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/libcairo-swt.so diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc Binary files differnew file mode 100644 index 0000000000..0cc5c65455 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc.ini b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc.ini new file mode 100644 index 0000000000..19ceb6f717 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86/qpidmc.ini @@ -0,0 +1,37 @@ +############################################################################### +# 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. +############################################################################### + +-vmargs +-Xms40m +-Xmx256m +-XX:MaxPermSize=256m +-Dosgi.requiredJavaVersion=1.5 +-Declipse.consoleLog=true + +#=============================================== +# SSL trust store configuration options. +#=============================================== + +# Uncomment lines below to specify custom truststore for server SSL +# certificate verification, eg when using self-signed server certs. +# +#-Djavax.net.ssl.trustStore=<path.to.truststore> +#-Djavax.net.ssl.trustStorePassword=<truststore.password> + + diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/Configuration/config.ini b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/Configuration/config.ini new file mode 100644 index 0000000000..f437e830b5 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/Configuration/config.ini @@ -0,0 +1,49 @@ +###############################################################################
+# 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.
+###############################################################################
+
+#Product Runtime Configuration File + +osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui +eclipse.product=org.apache.qpid.management.ui.product +osgi.bundles.defaultStartLevel=4 +osgi.bundles=jmxremote.sasl, \ +qpid-management-common, \ +org.apache.qpid.management.ui, \ +com.ibm.icu, \ +org.eclipse.core.commands, \ +org.eclipse.core.contenttype, \ +org.eclipse.core.databinding, \ +org.eclipse.core.expressions, \ +org.eclipse.core.jobs, \ +org.eclipse.core.runtime@start, \ +org.eclipse.core.runtime.compatibility.registry, \ +org.eclipse.equinox.app,org.eclipse.equinox.common, \ +org.eclipse.equinox.preferences, \ +org.eclipse.equinox.registry, \ +org.eclipse.help, \ +org.eclipse.jface, \ +org.eclipse.jface.databinding, \ +org.eclipse.swt, \ +org.eclipse.swt.gtk.linux.x86_64, \ +org.eclipse.ui, \ +org.eclipse.ui.forms, \ +org.eclipse.ui.workbench, \ +org.eclipse.equinox.launcher, \ +org.eclipse.equinox.launcher.gtk.linux.x86_64, \ +org.apache.commons.codec diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/libcairo-swt.so b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/libcairo-swt.so Binary files differnew file mode 100644 index 0000000000..5734427fb8 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/libcairo-swt.so diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc Binary files differnew file mode 100644 index 0000000000..ff1f3a7507 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc.ini b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc.ini new file mode 100644 index 0000000000..19ceb6f717 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/linux-gtk-x86_64/qpidmc.ini @@ -0,0 +1,37 @@ +############################################################################### +# 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. +############################################################################### + +-vmargs +-Xms40m +-Xmx256m +-XX:MaxPermSize=256m +-Dosgi.requiredJavaVersion=1.5 +-Declipse.consoleLog=true + +#=============================================== +# SSL trust store configuration options. +#=============================================== + +# Uncomment lines below to specify custom truststore for server SSL +# certificate verification, eg when using self-signed server certs. +# +#-Djavax.net.ssl.trustStore=<path.to.truststore> +#-Djavax.net.ssl.trustStorePassword=<truststore.password> + + diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Configuration/config.ini b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Configuration/config.ini new file mode 100644 index 0000000000..3ac3aa20f3 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Configuration/config.ini @@ -0,0 +1,49 @@ +###############################################################################
+# 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.
+###############################################################################
+
+#Product Runtime Configuration File + +osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui +eclipse.product=org.apache.qpid.management.ui.product +osgi.bundles.defaultStartLevel=4 +osgi.bundles=jmxremote.sasl, \ +qpid-management-common, \ +org.apache.qpid.management.ui, \ +com.ibm.icu, \ +org.eclipse.core.commands, \ +org.eclipse.core.contenttype, \ +org.eclipse.core.databinding, \ +org.eclipse.core.expressions, \ +org.eclipse.core.jobs, \ +org.eclipse.core.runtime@start, \ +org.eclipse.core.runtime.compatibility.registry, \ +org.eclipse.equinox.app,org.eclipse.equinox.common, \ +org.eclipse.equinox.preferences, \ +org.eclipse.equinox.registry, \ +org.eclipse.help, \ +org.eclipse.jface, \ +org.eclipse.jface.databinding, \ +org.eclipse.swt, \ +org.eclipse.swt.carbon.macosx, \ +org.eclipse.ui, \ +org.eclipse.ui.forms, \ +org.eclipse.ui.workbench, \ +org.eclipse.equinox.launcher, \ +org.eclipse.equinox.launcher.carbon.macosx, \ +org.apache.commons.codec diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Info.plist b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Info.plist new file mode 100644 index 0000000000..c6482a9254 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Info.plist @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<!-- + - + - 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. + - + --> +<plist version="1.0"> +<dict> + <key>CFBundleExecutable</key> + <string>qpidmc</string> + <key>CFBundleGetInfoString</key> + <string>Apache Qpid Management Console for Mac OS X</string> + <key>CFBundleIconFile</key> + <string>Console.icns</string> + <key>CFBundleIdentifier</key> + <string>org.apache.qpid.management.ui</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>Qpid Management Console</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>3.4</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>3.4</string> + <key>Qpid Management Console</key> + <array> + <string>-consoleLog</string> + <string>-showlocation</string> + <!-- WARNING: + If you try to add a single VM argument (-vmargs) here, + *all* vmargs specified in qpidmc.ini will be ignored. + We recommend to add all arguments in MacOS/qpidmc.ini --> + </array> +</dict> +</plist> diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc Binary files differnew file mode 100755 index 0000000000..36247a08e4 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc.ini b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc.ini new file mode 100644 index 0000000000..2a31b9b2c7 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/MacOS/qpidmc.ini @@ -0,0 +1,42 @@ +############################################################################### +# 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. +############################################################################### + +-startup +../../plugins/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar +--launcher.library +../../plugins/org.eclipse.equinox.launcher.carbon.macosx_1.0.101.R34x_v20080731 +-vmargs +-XstartOnFirstThread +-Xms40m +-Xmx512m +-XX:MaxPermSize=256m +-Dosgi.requiredJavaVersion=1.5 +-Declipse.consoleLog=true +-Dorg.eclipse.swt.internal.carbon.smallFonts + +#=============================================== +# SSL trust store configuration options. +#=============================================== + +# Uncomment lines below to specify custom truststore for server SSL +# certificate verification, eg when using self-signed server certs. +# +#-Djavax.net.ssl.trustStore=<path.to.truststore> +#-Djavax.net.ssl.trustStorePassword=<truststore.password> + diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Resources/Console.icns b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Resources/Console.icns Binary files differnew file mode 100644 index 0000000000..610976efab --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/macosx/Contents/Resources/Console.icns diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Configuration/config.ini b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Configuration/config.ini new file mode 100644 index 0000000000..a99a8b3f7d --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Configuration/config.ini @@ -0,0 +1,49 @@ +###############################################################################
+# 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.
+###############################################################################
+
+#Product Runtime Configuration File + +osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui +eclipse.product=org.apache.qpid.management.ui.product +osgi.bundles.defaultStartLevel=4 +osgi.bundles=jmxremote.sasl, \ +qpid-management-common, \ +org.apache.qpid.management.ui, \ +com.ibm.icu, \ +org.eclipse.core.commands, \ +org.eclipse.core.contenttype, \ +org.eclipse.core.databinding, \ +org.eclipse.core.expressions, \ +org.eclipse.core.jobs, \ +org.eclipse.core.runtime@start, \ +org.eclipse.core.runtime.compatibility.registry, \ +org.eclipse.equinox.app,org.eclipse.equinox.common, \ +org.eclipse.equinox.preferences, \ +org.eclipse.equinox.registry, \ +org.eclipse.help, \ +org.eclipse.jface, \ +org.eclipse.jface.databinding, \ +org.eclipse.swt, \ +org.eclipse.swt.gtk.solaris.sparc, \ +org.eclipse.ui, \ +org.eclipse.ui.forms, \ +org.eclipse.ui.workbench, \ +org.eclipse.equinox.launcher, \ +org.eclipse.equinox.launcher.gtk.solaris.sparc, \ +org.apache.commons.codec diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.l.pm b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.l.pm new file mode 100644 index 0000000000..995d7c9bb0 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.l.pm @@ -0,0 +1,311 @@ +/* XPM */ +static char *ProductIcon48[] = { +/* columns rows colors chars-per-pixel */ +"48 48 257 2", +" c black", +". c gray100", +"X c #69695A5AE8E8", +"o c #494949499191", +"O c #CECE9292BFBF", +"+ c #E7E7CACAE0E0", +"@ c #C8C88C8CBBBB", +"# c #C2C28A8ABABA", +"$ c #EAEAD7D7E8E8", +"% c #CFCFA9A9CCCC", +"& c #D9D9BCBCD8D8", +"* c #B6B68787B9B9", +"= c #C3C39999C7C7", +"- c #A7A77D7DB5B5", +"; c #BDBDA3A3CDCD", +": c #D8D8CACAE3E3", +"> c #A8A88D8DC4C4", +", c #92927575B2B2", +"< c #87876C6CAAAA", +"1 c #9A9A8383BABA", +"2 c #7B7B6363A3A3", +"3 c #666654549595", +"4 c #73735F5FADAD", +"5 c #626251519292", +"6 c #7F7F7272A7A7", +"7 c #6D6D5E5E9E9E", +"8 c #64645454A9A9", +"9 c #77776969B1B1", +"0 c #49493E3E8282", +"q c #7D7D7373B6B6", +"w c #5B5B4E4EADAD", +"e c #55554949BABA", +"r c #56564949BABA", +"t c #56564A4ABABA", +"y c #56564949B9B9", +"u c #55554949B8B8", +"i c #4F4F4444ACAC", +"p c #53534848B4B4", +"a c #53534848B3B3", +"s c #54544949B5B5", +"d c #52524747B0B0", +"f c #52524747AFAF", +"g c #54544949B3B3", +"h c #DEDEDCDCEEEE", +"j c #3E3E36369898", +"k c #43433B3B9F9F", +"l c #33332C2C7777", +"z c #42423A3A9C9C", +"x c #4A4A4040A8A8", +"c c #55554A4ABABA", +"v c #55554A4AB9B9", +"b c #54544949B7B7", +"n c #52524848B1B1", +"m c #51514747AEAE", +"M c #4E4E4545A9A9", +"N c #49494141A0A0", +"B c #52524848AFAF", +"V c #51514848AEAE", +"C c #50504747ACAC", +"Z c #4F4F4646AAAA", +"A c #51514848ADAD", +"S c #50504747ABAB", +"D c #50504848ACAC", +"F c #50504747A9A9", +"G c #4E4E4646A7A7", +"H c #4E4E4545A4A4", +"J c #4D4D4545A4A4", +"K c #4F4F4747A8A8", +"L c #4E4E4646A5A5", +"P c #4D4D4545A3A3", +"I c #3B3B35357D7D", +"U c #4E4E4646A3A3", +"Y c #55554D4D9F9F", +"T c #4A4A43438989", +"R c #51514B4B9090", +"E c #67676060A5A5", +"W c #1D1D18186A6A", +"Q c #272722227D7D", +"! c #282823237D7D", +"~ c #2B2B26268181", +"^ c #33332C2C8989", +"/ c #3B3B36368E8E", +"( c #454540409797", +") c #4D4D4646A4A4", +"_ c #4C4C4545A1A1", +"` c #4D4D4646A2A2", +"' c #4B4B4545A0A0", +"] c #4D4D4646A1A1", +"[ c #4C4C45459F9F", +"{ c #4B4B45459E9E", +"} c #4A4A44449C9C", +"| c #494944449898", +" . c #484843439696", +".. c #4A4A45459999", +"X. c #4F4F4A4AA0A0", +"o. c #68686363AAAA", +"O. c #21211D1D7676", +"+. c #242420207575", +"@. c #2D2D2A2A7F7F", +"#. c #2D2D2A2A7B7B", +"$. c #3D3D39398F8F", +"%. c #484844449696", +"&. c #474743439393", +"*. c #464643439191", +"=. c #454542428E8E", +"-. c #4D4D4A4A9C9C", +";. c #57575454A3A3", +":. c #5A5A58589797", +">. c #5F5F5D5D9999", +",. c #85858282C1C1", +"<. c #95959292C9C9", +"1. c #B8B8B6B6DCDC", +"2. c #070705055353", +"3. c #080807075555", +"4. c #0A0A09095757", +"5. c #0C0C0B0B5858", +"6. c #0F0F0D0D5C5C", +"7. c #10100F0F5C5C", +"8. c #131311116464", +"9. c #141413136060", +"0. c #141413135F5F", +"q. c #171715156767", +"w. c #161615156262", +"e. c #161615156161", +"r. c #181817176464", +"t. c #1A1A19196666", +"y. c #1C1C1A1A6464", +"u. c #1D1D1C1C6868", +"i. c #1F1F1E1E6A6A", +"p. c #222221216C6C", +"a. c #242423236F6F", +"s. c #272725257171", +"d. c #272726267272", +"f. c #272726267171", +"g. c #292928287474", +"h. c #2A2A29297474", +"j. c #2C2C2B2B7777", +"k. c #2F2F2E2E7C7C", +"l. c #2E2E2D2D7979", +"z. c #343433337E7E", +"x. c #393937378686", +"c. c #373736368181", +"v. c #3A3A39398484", +"b. c #3A3A39398383", +"n. c #3D3D3B3B8686", +"m. c #424241418C8C", +"M. c #424241418B8B", +"N. c #444442428B8B", +"B. c #434341418989", +"V. c #454544448E8E", +"C. c #454544448D8D", +"Z. c #424241418787", +"A. c #434342428888", +"S. c #444442428787", +"D. c #424241418585", +"F. c #414140408383", +"G. c #484847479090", +"H. c #434342428686", +"J. c #4A4A49499393", +"K. c #464645458A8A", +"L. c #4D4D4C4C9595", +"P. c #54545252A0A0", +"I. c #50504F4F9898", +"U. c #58585757A0A0", +"Y. c #525250509393", +"T. c #5B5B5959A2A2", +"R. c #585857579F9F", +"E. c #62626161A9A9", +"W. c #64646363ACAC", +"Q. c #6B6B6A6AB2B2", +"!. c #6B6B6A6AB1B1", +"~. c #75757474B8B8", +"^. c #7F7F7D7DBDBD", +"/. c #9C9C9B9BCFCF", +"(. c #0B0B0B0B5858", +"). c #0D0D0D0D5A5A", +"_. c #111111115E5E", +"`. c #131313136060", +"'. c #212121216D6D", +"]. c #242424246F6F", +"[. c #2B2B2C2C7777", +"{. c #2B2B2B2B7777", +"}. c #2C2C2C2C7777", +"|. c #2E2E2E2E7979", +" X c #313131317C7C", +".X c #313131317B7B", +"XX c #343434347E7E", +"oX c #3C3C3C3C8686", +"OX c #3F3F3F3F8989", +"+X c #414142428B8B", +"@X c #424242428B8B", +"#X c #474747479090", +"$X c #414141418484", +"%X c #404040408181", +"&X c #4A4A4A4A9494", +"*X c #4A4A4A4A9393", +"=X c #4D4D4D4D9696", +"-X c #4F4F4F4F9898", +";X c #505050509898", +":X c #525252529B9B", +">X c #555555559E9E", +",X c #555555559D9D", +"<X c #57575858A0A0", +"1X c #58585858A0A0", +"2X c #575758589F9F", +"3X c #575757579F9F", +"4X c #5A5A5A5AA2A2", +"5X c #5D5D5D5DA5A5", +"6X c #5F5F5F5FA7A7", +"7X c #61616262AAAA", +"8X c #61616161A9A9", +"9X c #61616262A9A9", +"0X c #62626262AAAA", +"qX c #64646464ACAC", +"wX c #62626262A9A9", +"eX c #64646464ABAB", +"rX c #66666666AEAE", +"tX c #66666666ADAD", +"yX c #68686868B0B0", +"uX c #69696969AFAF", +"iX c #6D6D6D6DB4B4", +"pX c #6F6F6F6FB5B5", +"aX c #73737373BABA", +"sX c #71717171B7B7", +"dX c #76767676BCBC", +"fX c #79797979BFBF", +"gX c #77777777B9B9", +"hX c #80808080C1C1", +"jX c #8C8C8C8CC5C5", +"kX c #90909090C9C9", +"lX c #98989898CBCB", +"zX c #A0A0A0A0CFCF", +"xX c #A5A5A5A5D3D3", +"cX c #ABABABABD6D6", +"vX c #C4C4C4C4E3E3", +"bX c #D1D1D1D1E9E9", +"nX c #E5E5E5E5F3F3", +"mX c #9F9FA0A0D1D1", +"MX c #B6B6C5C5E5E5", +"NX c #8E8EA6A6D6D6", +"BX c #9090A7A7D7D7", +"VX c #9191A9A9D7D7", +"CX c #9595ABABD8D8", +"ZX c #9999AFAFDADA", +"AX c #9D9DB2B2DCDC", +"SX c #A1A1B5B5DDDD", +"DX c #A5A5B8B8DEDE", +"FX c #A9A9BBBBE0E0", +"GX c #ACACBDBDE1E1", +"HX c #B0B0C1C1E3E3", +"JX c #B4B4C4C4E4E4", +"KX c #B8B8C7C7E5E5", +"LX c #BBBBC9C9E6E6", +"PX c #AEAEC0C0E2E2", +"IX c #B2B2C3C3E3E3", +"UX c gray100", +"YX c None", +/* pixels */ +"YXX X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X YX", +"X %X%X%XF.F.F.F.$XD.Z.Z.Z.B.B.B.N.N.=.=.=.*.*.*.&.&. . .| ....} } { { _ _ P P H G G G K S S C o ", +"X %X%X%X%XF.F.$XD.D.Z.Z.B.A.B.N.N.N.=.=.=.*.*.&.&.%.%.%.| | ..} { { [ _ _ ` U J L G K F Z S C o ", +"X %X%X%X%XF.F.F.D.D.H.Z.Z.A.B.N.N.N.C.=.=.*.*.&.&. . .%.| | ..} } { [ [ _ P P H G G K F S S C o ", +"X %XF.%XF.F.$XF.$XZ.Z.Z.B.A.K.Y.7 , - - 1 1 ^.^.~.aX~.q 9 6XY { } { ' _ ] P P H L G K F Z S C o ", +"X %XF.F.F.F.F.D.D.Z.Z.Z.K.:.1 ; % ; <.hXfXfXdXaXaXsXpXiX!.yXrXo.;.X.[ _ _ ` H H G K K F S S C o ", +"X F.F.F.F.F.D.D.D.Z.H.Y.1 & & 1.cXmX/.kXfXdXaXaXsXpXiXQ.yXtXeXE.6X5XP.X._ ` J L G G K F Z S C o ", +"X D.$XF.$XD.D.Z.Z.S.>.% + : vX1.1.cXmX/.dXaXaXsXpXiXQ.uXrXqX8X6X5XT.R.P.X.P ) H G K K S S S m o ", +"X D.$XD.D.D.D.D.S.6 & $ h bXvXvX1.xX/.kXfXaXsXpXiXQ.yXrXW.E.6X5X4XU.,X:XI.-.` L G G K F Z C C o ", +"X D.D.D.D.D.Z.H.6 & $ h h h bXvX1.cXmXkX,.dXpXiXQ.yXtXqXwX6X5XT.U.,X:XI.=X*X..` G K K Z S S m o ", +"X Z.D.Z.H.Z.Z.7 & $ h h nXh bXvX1.cXmXkX,.gXiXQ.uXrXW.E.6X5X4XU.,X:X-XL.J.#XV. .P G F S S C m o ", +"X Z.Z.Z.H.Z.R % + : bXh h h bXvX1.cX/.kXhX~.Q.yXrXqX9X6X5X4X2X,X:X;X=X*X#XV.M.OX( K Z S S C m o ", +"X Z.Z.Z.A.A.* & & vXvXbXbXbXvXvX1.xXlXjX^.pXuXrXeXwX6X5X4XU.,X:X-XL.*XG.V.@XOXoXb.( Z S C C V o ", +"X B.B.B.A.2 % % 1.1.vXvXvXvXvX1.cXzX<.,.gXiXrXW.E.6X5X4XU.,X:XI.=X*X#XV.@XOXn.b.c.x.N S S C m o ", +"X B.B.B.S.* % ; xX1.1.1.1.1.cXcXzXlXjX^.pXrXeX7X6X5X4XR.,X:X-XL.J.#XV.@XOXn.b.c.XX X$.S C C m o ", +"X N.N.N.2 O = /.mXxXcXcXcXcXxXzXlXjXhX~.uXeXE.6X5X4XU.,X:X-XL.J.#XV.M.OXn.v.c.z. X|.k.N D V f o ", +"X N.N.N.- @ > kX<././.mXzXzXlX<.jXhXgXuXeXE.6X5X4X1X,X:XI.L.*X#XV.m.OXn.b.c.z. Xl.j.g./ C m V o ", +"X N.N.R @ # ,.,.jXkXkX<.kXkXjX,.^.~.uXwXE.6X5X4X1X,X:XI.=XJ.#XC.M.OXn.v.c.z..X|.j.g.d.#.M m B o ", +"X =.M.< @ * fXfXhXhX,.,.,.hX^.gXpXuXqX9X6X5X4XU.,X:XI.L.*XG.V.+XOXn.b.c.z..X|.[.g.d.a.p.z V B o ", +"X =.N.- @ NXNXBXBXBXVXCXCXCXCXZXZXZXZXAXAXSXSXSXDXDXDXFXFXFXGXPXPXHXHXIXJXMXMXMXKXKXLXLXLXB d o ", +"X =.=.* @ 1 dXdXaXaXsXpXiX!.yXrXeXwX6X5X4X<X,X:XI.=X*XG.V.M.OXn.v.c.XX.X|.j.g.d.a.p.i.u.@.f d o ", +"X *.=.# @ ^.dXaXaXsXpXiXQ.yXrXeXwX6X5XT.U.,X:X-XL.&XG.C.m.OXoXv.c.z..X|.j.g.f.a.p.i.u.t.+.d d o ", +"X *.*.@ @ NXNXNXBXVXVXCXCXCXCXZXZXZXZXAXAXAXSXSXDXDXDXFXFXGXGXPXPXHXHXJXJXJXMXKXKXKXLXLXLXd n o ", +"X &.*.@ @ dXaXsXpXiXQ.yXtXeXE.6X5X4XU.>X:XI.L.*XG.V.m.OXoXv.c.z. X|.j.g.d.a.'.i.u.t.r.w.9.d n o ", +"X &.&.@ @ ~.sXpXiXQ.yXtXW.E.6X5X4X1X,X:XI.=X*X#XC.m.OXn.b.c.z. X|.[.g.f.a.p.i.u.t.r.w.9.0.n a o ", +"X &.&.@ @ NXNXBXBXVXVXVXCXCXCXZXZXZXZXAXAXSXSXSXDXDXDXFXFXGXGXPXPXHXIXIXJXMXMXKXKXKXLXLXLXn n o ", +"X %. .# @ q iXQ.yXrXW.0X6X5X4XU.>X:XI.L.*X#XV.@XOXn.b.c.XX.X|.{.g.f.].'.i.u.t.r.w.0._.7.W n a o ", +"X %. .* # , Q.yXtXeX7X6X5X4XU.,X:X-XL.*X#XV.@XOXn.b.c.XX Xl.{.g.d.a.p.i.u.t.r.e.0._.7.).+.a a o ", +"X | | - # NXNXNXBXVXVXCXCXCXCXZXZXZXAXAXAXAXSXSXDXDXDXFXFXGXGXPXPXHXHXIXJXMXMXMXKXKXLXLXLXa a o ", +"X | | < # - rXeX9X6X5X4XU.,X:X-XL.*X#XC.@XOXoXb.c.z. X|.j.h.s.a.'.i.u.t.r.w.9._.7.).5.4.j a p o ", +"X | } Y # * 9 8X6X5X4X3X,X:XI.=X*XG.V.@XOXn.v.c.XX X|.j.g.f.a.p.i.u.t.r.e.0._.7.).5.4.q.i g p o ", +"X } } | - # , 6X5X4XR.,X:XI.=X*XG.V.m.OXoXb.c.XX X|.j.g.f.a.p.i.u.t.r.e.9._.7.).5.4.3.~ a s s o ", +"X } } } 4 # - E 4XU.>X:X-X=XJ.#XV.M.OXoXb.c.XX X|.{.h.d.a.'.i.u.t.r.e.9._.7.).5.4.3.6.z p s s o ", +"X { { } } - # < U.,X:XI.=X*XG.V.+XOXoXb.c.z. X|.}.g.d.a.'.i.u.t.r.w.0._.7.).5.4.3.2.! g p s s o ", +"X [ { ' [ 4 * - E :X;XL.J.#XV.m.OXoXb.c.z..X|.j.h.f.a.'.i.u.t.r.w.9._.6.).(.4.3.2.8.k p s s s o ", +"X [ [ ' _ [ , * , ;XL.J.#XV.@XOXoXv.c.z..X|.{.g.f.a.p.i.u.t.r.w.`._.7.).(.4.3.2.2.^ s p s s s o ", +"X _ _ _ _ P ] - * 2 *X#XV.m.OXn.v.c.XX X|.j.h.f.a.p.i.u.t.r.w.`._.7.).(.4.3.2.2.Q p s s s b u o ", +"X ` ` ` ` ` ` 8 - - 7 V.@XOXoXv.c.XX.X|.j.g.d.a.'.i.u.t.r.w.0._.7.).5.4.3.2.2.O.x p s s s u u o ", +"X P P ) P U U ) 8 - - 7 OXn.v.c.XX X|.j.h.f.a.p.i.u.t.r.w.0._.7.).5.4.3.2.2.O.x s s s s b u u o ", +"X L L ) H ) L L L 8 1 - 7 b.c.z. X|.j.h.f.a.'.i.u.t.r.w.0._.7.).5.4.3.2.2.Q x p s s s b b u e o ", +"X L G L G G G G G G G , * 2 T .Xl.j.h.f.a.p.i.u.t.r.e.0._.7.).5.4.3.2.8.^ p p s s s s u u e e o ", +"X G G G G G G G K K M M 4 , , 3 I g.d.a.p.i.u.t.r.e.`._.7.).5.4.3.7.! k p s p s s s u u u e v o ", +"X K G K K K K K K Z Z M F F 4 , < 3 I p.i.u.t.r.w.9._.7.).5.4.W ~ z a p p s s b s u u u e e e o ", +"X F Z F F F F Z Z F F S S S S S w 9 < 2 5 0 l p.e.9.y.a.l ^ j i a p p p s s b b b u e v y r e o ", +"X S Z Z S Z S Z S S S S S C C C A m d V f m B m B d d n d a a a p s p s s b u u u u e v e r t o ", +"X S S S S S S S S S S C C C m m A V V B B B d d d n n a a a p p s p s s b u u u e e e c t r t o ", +"X C C C C C C C C m C A m A m f V f f B d d d n n n a a a a s s s s s u b u u u u v t t r t t o ", +"YXo o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o YX" +}; diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.m.pm b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.m.pm new file mode 100644 index 0000000000..e64aa0cc06 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.m.pm @@ -0,0 +1,295 @@ +/* XPM */ +static char *ProductIcon32[] = { +/* columns rows colors chars-per-pixel */ +"32 32 257 2", +" c black", +". c gray100", +"X c #69695A5AE8E8", +"o c #494949499191", +"O c #E8E8CBCBE0E0", +"+ c #DDDDB3B3D2D2", +"@ c #F0F0DDDDEBEB", +"# c #CDCD9191BEBE", +"$ c #C8C88B8BBBBB", +"% c #CACA9898C2C2", +"& c #C3C38A8ABBBB", +"* c #BABA8787B9B9", +"= c #DCDCC4C4DEDE", +"- c #C5C5A3A3CACA", +"; c #ADAD8181B8B8", +": c #A3A37A7AB5B5", +"> c #E2E2D6D6E9E9", +", c #B3B39A9AC4C4", +"< c #EBEBE3E3F0F0", +"1 c #C9C9B6B6D6D6", +"2 c #96967676B8B8", +"3 c #8C8C7171ABAB", +"4 c #A4A49292BEBE", +"5 c #7D7D6565A6A6", +"6 c #83836D6DABAB", +"7 c #9A9A8787C2C2", +"8 c #7B7B6464B7B7", +"9 c #5E5E50509191", +"0 c #646457579A9A", +"q c #85857B7BBEBE", +"w c #7C7C7373B6B6", +"e c #62625353D5D5", +"r c #61615353D4D4", +"t c #60605252D1D1", +"y c #5F5F5252D0D0", +"u c #5F5F5151CFCF", +"i c #60605353D2D2", +"p c #5F5F5252CFCF", +"a c #5E5E5151CDCD", +"s c #5C5C4F4FC7C7", +"d c #5F5F5252CDCD", +"f c #5E5E5151CBCB", +"g c #5B5B4F4FC4C4", +"h c #5A5A4E4EC1C1", +"j c #71716969B0B0", +"k c #48483E3EADAD", +"l c #5D5D5151CDCD", +"z c #5C5C5050C9C9", +"x c #5D5D5151CBCB", +"c c #5C5C5050C7C7", +"v c #5B5B4F4FC6C6", +"b c #5B5B5050C6C6", +"n c #59594E4EC1C1", +"m c #58584D4DBFBF", +"M c #59594F4FC2C2", +"N c #5A5A4F4FC2C2", +"B c #58584D4DBCBC", +"V c #57574D4DBCBC", +"C c #59594E4EBEBE", +"Z c #58584E4EBDBD", +"A c #58584D4DBBBB", +"S c #57574D4DBABA", +"D c #56564D4DB9B9", +"F c #56564C4CB6B6", +"G c #55554C4CB6B6", +"H c #54544B4BB4B4", +"J c #54544B4BB1B1", +"K c #53534B4BB1B1", +"L c #52524A4AAEAE", +"P c #51514949ACAC", +"I c #51514949ABAB", +"U c #474741418787", +"Y c #32322C2C8F8F", +"T c #2B2B25257777", +"R c #36362F2F9696", +"E c #2B2B26266E6E", +"W c #4D4D4545ACAC", +"Q c #55554D4DB8B8", +"! c #54544C4CB4B4", +"~ c #54544C4CB3B3", +"^ c #51514A4AACAC", +"/ c #51514A4AABAB", +"( c #50504949A9A9", +") c #4F4F4949A6A6", +"_ c #4C4C4747A1A1", +"` c #4E4E4848A3A3", +"' c #4D4D4848A1A1", +"] c #4B4B46469C9C", +"[ c #4C4C47479E9E", +"{ c #51514C4CA6A6", +"} c #A9A9A6A6D5D5", +"| c #1E1E1A1A6666", +" . c #292925258181", +".. c #3D3D39399292", +"X. c #4A4A46469B9B", +"o. c #53534E4EABAB", +"O. c #494945459797", +"+. c #4A4A46469999", +"@. c #474744449494", +"#. c #484845459494", +"$. c #474744449292", +"%. c #464643439090", +"&. c #464642428D8D", +"*. c #54545050A9A9", +"=. c #474744448F8F", +"-. c #4C4C49499999", +";. c #57575454A6A6", +":. c #5B5B5757AAAA", +">. c #545451519B9B", +",. c #5A5A57579C9C", +"<. c #65656262A7A7", +"1. c #68686666A2A2", +"2. c #CACAC9C9E5E5", +"3. c #050504045151", +"4. c #080807075454", +"5. c #0A0A09095858", +"6. c #0C0C0A0A5858", +"7. c #10100E0E6262", +"8. c #0E0E0D0D5A5A", +"9. c #121211115D5D", +"0. c #131312125D5D", +"q. c #161615156161", +"w. c #171716166161", +"e. c #1A1A19196565", +"r. c #20201E1E7070", +"t. c #1E1E1D1D6969", +"y. c #2A2A29297676", +"u. c #2F2F2D2D7676", +"i. c #3A3A39398787", +"p. c #3A3A39398383", +"a. c #3F3F3E3E8888", +"s. c #414140408989", +"d. c #454543438D8D", +"f. c #444442428B8B", +"g. c #444443438C8C", +"h. c #434342428A8A", +"j. c #434341418888", +"k. c #434342428989", +"l. c #424241418787", +"z. c #434342428787", +"x. c #424241418585", +"c. c #41413F3F8181", +"v. c #414140408282", +"b. c #484846468D8D", +"n. c #494948489090", +"m. c #4B4B4A4A9191", +"M. c #4B4B49498E8E", +"N. c #525251519A9A", +"B. c #525251519999", +"V. c #565654549A9A", +"C. c #545453539494", +"Z. c #60605F5FA7A7", +"A. c #64646363ABAB", +"S. c #5A5A59599797", +"D. c #68686767ADAD", +"F. c #6C6C6B6BB2B2", +"G. c #5E5E5D5D9A9A", +"H. c #76767575BABA", +"J. c #78787777BBBB", +"K. c #76767474B5B5", +"L. c #7E7E7D7DBABA", +"P. c #A5A5A4A4D2D2", +"I. c #040404045252", +"U. c #070707075454", +"Y. c #070708085353", +"T. c #080808085454", +"R. c #0A0A0B0B5757", +"E. c #0E0E0E0E5A5A", +"W. c #111112125E5E", +"Q. c #111111115E5E", +"!. c #111111115D5D", +"~. c #111112125D5D", +"^. c #161616166868", +"/. c #151516166161", +"(. c #151515156161", +"). c #19191A1A6565", +"_. c #191919196565", +"`. c #1A1A1A1A6464", +"'. c #1D1D1E1E6969", +"]. c #1E1E1E1E6969", +"[. c #222222226D6D", +"{. c #272727277171", +"}. c #2B2B2C2C7676", +"|. c #2B2B2B2B7676", +" X c #2B2B2B2B7575", +".X c #303030307A7A", +"XX c #303030307979", +"oX c #353535357F7F", +"OX c #393939398383", +"+X c #3A3A3A3A8383", +"@X c #3F3F3F3F8787", +"#X c #434343438C8C", +"$X c #434344448C8C", +"%X c #424242428686", +"&X c #414141418484", +"*X c #484848489191", +"=X c #484849499090", +"-X c #4D4D4D4D9696", +";X c #515151519D9D", +":X c #4D4D4D4D9595", +">X c #515152529A9A", +",X c #515152529999", +"<X c #525252529A9A", +"1X c #525252529999", +"2X c #565657579E9E", +"3X c #575757579D9D", +"4X c #5B5B5B5BA2A2", +"5X c #5F5F6060A6A6", +"6X c #5F5F5F5FA6A6", +"7X c #63636464AAAA", +"8X c #64646464AAAA", +"9X c #67676767AEAE", +"0X c #67676868AEAE", +"qX c #68686868AEAE", +"wX c #6F6F6F6FB5B5", +"eX c #6C6C6C6CB1B1", +"rX c #73737373B8B8", +"tX c #82828282BEBE", +"yX c #86868686C2C2", +"uX c #89898989C4C4", +"iX c #98989898CBCB", +"pX c #A0A0A0A0CFCF", +"aX c #A9A9A9A9D5D5", +"sX c #B0B0B0B0D8D8", +"dX c #B8B8B8B8DDDD", +"fX c #BDBDBDBDE0E0", +"gX c #D9D9D9D9EDED", +"hX c #90909191C6C6", +"jX c #71718989BCBC", +"kX c #73738B8BBFBF", +"lX c #72728989BCBC", +"zX c #79799090C3C3", +"xX c #7E7E9595C7C7", +"cX c #81819898CACA", +"vX c #84849B9BCCCC", +"bX c #8C8CA3A3D4D4", +"nX c #71718A8ABCBC", +"mX c #73738B8BBDBD", +"MX c #75758D8DBFBF", +"NX c #74748C8CBEBE", +"BX c #76768E8EC0C0", +"VX c #7C7C9494C6C6", +"CX c #7B7B9393C4C4", +"ZX c #7F7F9797C9C9", +"AX c #82829A9ACBCB", +"SX c #85859E9ECECE", +"DX c #8888A0A0D1D1", +"FX c #87879F9FD0D0", +"GX c #8B8BA4A4D4D4", +"HX c #8B8BA3A3D4D4", +"JX c #8989A1A1D2D2", +"KX c #8D8DA5A5D6D6", +"LX c #8B8BA3A3D3D3", +"PX c #8E8EA6A6D6D6", +"IX c #8D8DA5A5D5D5", +"UX c gray100", +"YX c None", +/* pixels */ +"YXX X X X X X X X X X X X X X X X X X X X X X X X X X X X X X YX", +"X v.v.v.v.&Xl.z.k.&.d.%.$.@.O.+.] [ _ ` ) ( ^ L K ! G D V m m o ", +"X c.c.c.v.&Xx.z.f.f.d.%.$.#.O.+.X.[ _ ` ) ( / L K H F D V C n o ", +"X v.c.v.v.x.x.z.k.f.n.V.,.>.-.+.] [ _ ` ) ( ^ L K H G D V C h o ", +"X &Xv.&Xx.x.l.j.M.1.4 - - , 7 q J.H.K.j :.*.P L K H F S B C n o ", +"X x.&Xx.x.z.j.S., = = 1 } iXuXH.rXwXF.qX7XZ.;.o.J ! F S B m n o ", +"X x.l.z.%Xz.G.1 @ > 2.dXaXiXuXrXwXF.qX8X5X4X2X;X{ H F S V C n o ", +"X z.j.j.j.C.1 @ < gX2.fXaXpXuXwXeX9X7X5X4X2XN.:X*X_ D S Z m h o ", +"X k.k.h.b., O > gXgX2.dXaXiXyXF.D.A.Z.4X3X1X:Xn.g.a._ V B m N o ", +"X f.f.f.3 + = 2.2.2.fXsXpXhXtXD.8XZ.4X2X1X:X*X$X@Xp.i.W C n N o ", +"X d.&.%.% + 1 dXdXdXsXP.iXyXK.8X5X4X2X>X:X*Xg.a.+XoX.X..m n N o ", +"X %.=.5 % - P.} aXP.pXiXyXK.D.Z.4X3X1X-Xn.$X@X+XoX.X Xy.W h g o ", +"X $.$.: # PXIXGXGXLXJXFXFXSXvXAXcXZXxXVXCXzXzXBXMXkXmXnXjXh g o ", +"X #.@.* $ 7 yXuXyXtXL.K.D.6X4X2X1X:Xo g.a.OXoX.X|.{.[.t. .g v o ", +"X O.#.$ $ q H.rXwXF.0XA.6X4X2X1X:Xo $Xa.p.oX.X|.{.[.'.`.r.g b o ", +"X X.+.$ $ PXKXbXbXLXJXDXFXSXvXAXcXZXxXCXCXzXBXBXMXNXmXlXjXb c o ", +"X ] ] $ $ H.wXF.0X7X6X4X2X<X:Xo #Xa.+XoX.X|.{.[.].)./.~.Q.c z o ", +"X [ [ & & w F.qX7XZ.4X2X,X:Xo #Xa.+XoX.X}.{.[.'.e./.9.E.^.c z o ", +"X ' _ * & PXKXbXHXLXJXDXSXSXvXAXcXZXxXVXCXzXzXBXMXNXkXjXjXz x o ", +"X ` ` : & 2 8XZ.4X2XB.:X*Xg.@Xp.oX.X|.{.[.].).q.!.E.R.U.Y z f o ", +"X ) ) 5 & ; <.4X2X>X:Xo #Xa.+XoXXX|.{.[.t._.q.~.E.R.4.5.k x a o ", +"X ( ( I ; * 6 2X>X:X=X$X@X+XoX.X|.{.[.t.e./.W.E.R.Y.3. .z a a o ", +"X I ^ / 8 * : 0 :X*X#X@X+XoX.X|.{.[.'._.(.~.E.R.T.3.7.k x a p o ", +"X L L L ^ 2 * 3 m.$Xa.p.oX.X}.{.[.t.).(.~.E.6.T.3.I.R x a a y o ", +"X J K K K K 2 * 5 s.OXoX.X}.{.[.'._.(.9.8.R.4.3.I.Y x l a p t o ", +"X ~ H H ! ! ! 2 ; 5 U XX}.{.[.].e.(.W.E.R.U.3.7.R x l u u y t o ", +"X G F G G G Q Q 8 : 3 9 u.[.]._./.Q.E.R.T.6. .k x a a u t t t o ", +"X D S D S D S S S V 8 2 6 9 c.E w.0.| T Y k z z a a p t t i r o ", +"X A V B V V V B B m m n n h h g g g c z z z l l d p y t i r r o ", +"X m C C C C C C C n n n M N g g b c z z x a a a u y t t r r e o ", +"X n n n n n h h h N N g g v b s z z z x a p p u t t r r r e e o ", +"YXo o o o o o o o o o o o o o o o o o o o o o o o o o o o o o YX" +}; diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.s.pm b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.s.pm new file mode 100644 index 0000000000..e2b9379f3a --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.s.pm @@ -0,0 +1,287 @@ +/* XPM */ +static char *ProductIcon24[] = { +/* columns rows colors chars-per-pixel */ +"24 24 257 2", +" c black", +". c gray100", +"X c #69695A5AE8E8", +"o c #494949499191", +"O c #F1F1DFDFECEC", +"+ c #D7D7ACACCDCD", +"@ c #DFDFBBBBD6D6", +"# c #E2E2C4C4DBDB", +"$ c #CECE9C9CC4C4", +"% c #C4C48B8BBABA", +"& c #C2C28A8ABABA", +"* c #C4C48E8EBCBC", +"= c #BFBF8A8AB9B9", +"- c #EBEBD9D9E9E9", +"; c #BFBF8888B9B9", +": c #D8D8B9B9D6D6", +"> c #B9B98686B9B9", +", c #B8B88989B9B9", +"< c #BBBB9393BFBF", +"1 c #A9A97B7BB2B2", +"2 c #E4E4D4D4E7E7", +"3 c #C6C6AFAFCECE", +"4 c #A6A68080B6B6", +"5 c #A2A27E7EB4B4", +"6 c #9E9E7E7EB1B1", +"7 c #ABAB9090BBBB", +"8 c #B7B7A0A0C5C5", +"9 c #9D9D7C7CB2B2", +"0 c #AAAA8B8BBEBE", +"q c #AAAA9090BCBC", +"w c #8C8C6B6BABAB", +"e c #90907070B1B1", +"r c #C4C4B3B3D7D7", +"t c #CDCDBFBFDDDD", +"y c #EAEAE4E4F1F1", +"u c #88886A6AADAD", +"i c #9E9E8585C1C1", +"p c #84846A6AAFAF", +"a c #81816B6BAAAA", +"s c #D7D7CFCFE6E6", +"d c #81816969B1B1", +"f c #78786363A5A5", +"g c #6E6E5D5D9C9C", +"h c #717160609D9D", +"j c #83837474AAAA", +"k c #6A6A5757A3A3", +"l c #6E6E5E5EA0A0", +"z c #5E5E50509292", +"x c #88887B7BBCBC", +"c c #68685858ABAB", +"v c #5A5A4D4DA2A2", +"b c #7D7D7373B4B4", +"n c #5A5A4E4EA6A6", +"m c #5F5F56569595", +"M c #56564A4ABBBB", +"N c #56564949B9B9", +"B c #55554949B8B8", +"V c #53534848B3B3", +"C c #54544949B4B4", +"Z c #52524747B0B0", +"A c #52524747AFAF", +"S c #5B5B53539393", +"D c #3E3E36369797", +"F c #49494040A6A6", +"G c #48484040A5A5", +"H c #55554A4ABABA", +"J c #54544949B7B7", +"K c #53534949B4B4", +"L c #51514747AFAF", +"P c #52524848B1B1", +"I c #51514848B0B0", +"U c #51514848AEAE", +"Y c #51514747ADAD", +"T c #51514848ADAD", +"R c #4F4F4747ABAB", +"E c #50504747ABAB", +"W c #50504646A9A9", +"Q c #4F4F4646A8A8", +"! c #4E4E4646A7A7", +"~ c #4E4E4545A4A4", +"^ c #4D4D4545A4A4", +"/ c #4E4E4646A5A5", +"( c #4D4D4545A1A1", +") c #3D3D36367E7E", +"_ c #4B4B44449C9C", +"` c #2A2A25257F7F", +"' c #3E3E37379898", +"] c #474740409C9C", +"[ c #4D4D4646A4A4", +"{ c #4C4C4545A2A2", +"} c #4D4D4646A2A2", +"| c #4D4D4646A1A1", +" . c #4B4B45459F9F", +".. c #4C4C45459F9F", +"X. c #4C4C46469F9F", +"o. c #4B4B45459D9D", +"O. c #494943439898", +"+. c #494944449A9A", +"@. c #4A4A45459A9A", +"#. c #494944449898", +"$. c #484843439696", +"%. c #494944449797", +"&. c #484843439595", +"*. c #51514C4CA1A1", +"=. c #6B6B6767AEAE", +"-. c #95959191C9C9", +";. c #23231F1F7676", +":. c #21211E1E7070", +">. c #292925257F7F", +",. c #252521217070", +"<. c #242421216D6D", +"1. c #2B2B27278080", +"2. c #393935358C8C", +"3. c #444440409494", +"4. c #3B3B38388282", +"5. c #474743439494", +"6. c #484844449595", +"7. c #474743439393", +"8. c #474744449393", +"9. c #464643439191", +"0. c #454542428F8F", +"q. c #4A4A47479898", +"w. c #464643438F8F", +"e. c #454542428D8D", +"r. c #444441418B8B", +"t. c #484844449191", +"y. c #444441418989", +"u. c #494946469090", +"i. c #4C4C48489393", +"p. c #51514E4E9E9E", +"a. c #73737070B6B6", +"s. c #77777474BBBB", +"d. c #A0A09E9ED1D1", +"f. c #D6D6D5D5EBEB", +"g. c #0E0E0D0D5A5A", +"h. c #11110F0F5E5E", +"j. c #121211115E5E", +"k. c #131312125F5F", +"l. c #171716166363", +"z. c #1D1D1B1B6868", +"x. c #1D1D1C1C6868", +"c. c #222221216E6E", +"v. c #222221216D6D", +"b. c #282827277474", +"n. c #282827277373", +"m. c #292928287373", +"M. c #2F2F2E2E7979", +"N. c #353534347F7F", +"B. c #363635358181", +"V. c #3C3C3B3B8585", +"C. c #424241418C8C", +"Z. c #424241418B8B", +"A. c #444442428B8B", +"S. c #434341418989", +"D. c #434342428989", +"F. c #424241418787", +"G. c #414140408484", +"H. c #474745458D8D", +"J. c #434342428787", +"K. c #424241418585", +"L. c #414140408282", +"P. c #494948489191", +"I. c #4F4F4E4E9797", +"U. c #59595757A6A6", +"Y. c #5F5F5D5DA4A4", +"T. c #6C6C6B6BB3B3", +"R. c #7C7C7B7BB9B9", +"E. c #A8A8A7A7D3D3", +"W. c #0D0D0D0D5A5A", +"Q. c #1F1F1F1F6C6C", +"!. c #222222226E6E", +"~. c #3B3B3B3B8585", +"^. c #414141418C8C", +"/. c #414141418B8B", +"(. c #424242428B8B", +"). c #484848489292", +"_. c #404040408181", +"`. c #4E4E4E4E9898", +"'. c #555555559E9E", +"]. c #555555559D9D", +"[. c #5B5B5B5BA3A3", +"{. c #5C5C5C5CA3A3", +"}. c #61616161A9A9", +"|. c #66666666AEAE", +" X c #66666666ADAD", +".X c #6B6B6B6BB2B2", +"XX c #70707070B7B7", +"oX c #6A6A6A6AADAD", +"OX c #74747474BBBB", +"+X c #89898989C2C2", +"@X c #90909090C8C8", +"#X c #8F8F8F8FC6C6", +"$X c #92929292C6C6", +"%X c #9F9F9F9FCFCF", +"&X c #A5A5A5A5D2D2", +"*X c #B5B5B5B5DBDB", +"=X c #B8B8B8B8DEDE", +"-X c #B7B7B7B7DCDC", +";X c #BBBBBBBBDEDE", +":X c #BDBDBDBDDFDF", +">X c #C9C9C9C9E5E5", +",X c #D1D1D1D1EAEA", +"<X c #7C7C7D7DBABA", +"1X c #89898A8AC7C7", +"2X c #8F8F9090C7C7", +"3X c #A3A3A4A4D3D3", +"4X c #A2A2B5B5DEDE", +"5X c #ADADBDBDE1E1", +"6X c #B9B9C7C7E5E5", +"7X c #BABAC8C8E6E6", +"8X c #8E8EA6A6D6D6", +"9X c #9090A7A7D7D7", +"0X c #9191A9A9D7D7", +"qX c #9292A9A9D8D8", +"wX c #9494ABABD8D8", +"eX c #9898AEAED9D9", +"rX c #9B9BB0B0DADA", +"tX c #9E9EB3B3DCDC", +"yX c #A1A1B5B5DDDD", +"uX c #A5A5B8B8DEDE", +"iX c #A8A8BBBBE0E0", +"pX c #ACACBEBEE1E1", +"aX c #AFAFC0C0E3E3", +"sX c #B3B3C3C3E4E4", +"dX c #B2B2C2C2E3E3", +"fX c #B5B5C5C5E5E5", +"gX c #B8B8C7C7E6E6", +"hX c #B6B6C5C5E4E4", +"jX c #9797AEAED9D9", +"kX c #A1A1B6B6DDDD", +"lX c #A8A8BBBBDFDF", +"zX c gray100", +"xX c black", +"cX c black", +"vX c black", +"bX c black", +"nX c black", +"mX c black", +"MX c black", +"NX c black", +"BX c black", +"VX c black", +"CX c black", +"ZX c black", +"AX c black", +"SX c black", +"DX c black", +"FX c black", +"GX c black", +"HX c black", +"JX c black", +"KX c black", +"LX c black", +"PX c black", +"IX c black", +"UX c black", +"YX c None", +/* pixels */ +"YXX X X X X X X X X X X X X X X X X X X X X X YX", +"X _._.L.G.K.F.D.A.e.0.9.&.$.%.+._ ..{ ^ ! W E o ", +"X L.L.L.G.F.F.D.r.e.0.9.7.&.O.@.o. .{ ~ ! Q E o ", +"X L.G.G.K.F.S.y.r.e.w.9.5.$.+.@.o...( ~ ! W E o ", +"X G.K.K.F.J.D.h 6 0 i x s.a.=.U.*...} ~ ! W E o ", +"X K.F.F.F.S 7 : r d.1XOXXX.X|.}.[.p.| / ! W E o ", +"X F.F.F.m 3 - s =X3X@XXXT. X}.[.].I.q.{ Q E T o ", +"X S.D.H.8 O y ,X;X&X2X.X|.}.[.].I.P.C.3.Q E Y o ", +"X A.r.j # 2 f.>X*X%X+X|.}.[.].I.P.^.~.B.] E Y o ", +"X e.u.q @ t :X-XE.$X<X}.[.].`.P.Z.V.N.M.2.Y L o ", +"X 0.i.< + 8X8XqXwXeXrXtX4XuXlXpXaXsXfXgX7XY A o ", +"X 9.t.* $ -.#X+XR.oX{.'.`.P.(.~.N.M.m.c.Q.T Z o ", +"X 8.7.; % 8X9X0XwXeXrXtXyXuXiXpXaXdXfXgX7XL Z o ", +"X 6.&.1 & b X}.[.'.I.P./.~.N.M.n.!.x.l.:.I P o ", +"X #.#.w = 8X9XqXwXjXrXtXkXuXiX5XaXsXhX6X7XP V o ", +"X +.+.k > 5 Y.].I.)./.~.N.M.b.v.x.l.k.h.' V C o ", +"X o.o.o.u , a I.).Z.V.N.M.n.c.z.l.j.W.` P V C o ", +"X .. .X.v e 4 l ^.V.N.M.m.!.x.l.j.g.;.F V C J o ", +"X ( | ( ( n p 9 g 4.M.n.c.x.l.j.h.>.G V K C J o ", +"X ~ [ [ ^ / / c d f z ) <.z.,.1.D P V C C B B o ", +"X ! Q ! Q Q Q Q W E E Y T A Z P V V K C J B B o ", +"X Q W Q W R W E E T T T L Z P V V K J J J B N o ", +"X R E E E E E Y Y U L Z P P P C V J J B B H M o ", +"YXo o o o o o o o o o o o o o o o o o o o o o YX" +}; diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.t.pm b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.t.pm new file mode 100644 index 0000000000..3f6b21f428 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/Qpidmc.t.pm @@ -0,0 +1,279 @@ +/* XPM */ +static char *ProductIcon16[] = { +/* columns rows colors chars-per-pixel */ +"16 16 257 2", +" c black", +". c gray100", +"X c #E2E2C0C0D9D9", +"o c #EDEDD9D9E8E8", +"O c #D5D5ABABCDCD", +"+ c #E2E2C3C3DCDC", +"@ c #C5C58E8EBCBC", +"# c #D4D4ABABCDCD", +"$ c #CACA9F9FC6C6", +"% c #D6D6B4B4D3D3", +"& c #CACAA0A0C8C8", +"* c #C6C69D9DC6C6", +"= c #C5C59F9FC8C8", +"- c #CCCCACACCECE", +"; c #CCCCB0B0D3D3", +": c #A6A68383B3B3", +"> c #BABA9A9AC6C6", +", c #B7B79A9AC2C2", +"< c #E3E3D5D5E9E9", +"1 c #B0B08E8EC0C0", +"2 c #9F9F8080B8B8", +"3 c #AFAF9898C1C1", +"4 c #DBDBCFCFE5E5", +"5 c #96967878B2B2", +"6 c #9A9A7E7EBABA", +"7 c #8E8E7878AFAF", +"8 c #91917F7FBDBD", +"9 c #D3D3CCCCE4E4", +"0 c #535348488B8B", +"q c #69695A5AE8E8", +"w c #55554949B9B9", +"e c #55554949B8B8", +"r c #54544848B6B6", +"t c #53534848B4B4", +"y c #54544848B4B4", +"u c #53534848B3B3", +"i c #53534848B2B2", +"p c #52524747AFAF", +"a c #53534848B1B1", +"s c #54544949B8B8", +"d c #54544949B6B6", +"f c #52524848B3B3", +"g c #52524848B2B2", +"h c #53534949B3B3", +"j c #52524848B1B1", +"k c #52524848B0B0", +"l c #51514747AEAE", +"z c #52524848AFAF", +"x c #51514848AEAE", +"c c #51514747ADAD", +"v c #51514747ACAC", +"b c #4F4F4646AAAA", +"n c #51514848ADAD", +"m c #50504747ABAB", +"M c #50504747AAAA", +"N c #4F4F4646A8A8", +"B c #50504747A9A9", +"V c #4E4E4646A7A7", +"C c #4E4E4646A6A6", +"Z c #4F4F4646A6A6", +"A c #4F4F4747A7A7", +"S c #4D4D4545A3A3", +"D c #4D4D4545A2A2", +"F c #4C4C45459E9E", +"G c #74746E6EB3B3", +"H c #2E2E29298383", +"J c #383832329090", +"K c #464640409999", +"L c #4D4D4646A2A2", +"P c #4E4E4747A3A3", +"I c #4B4B45459F9F", +"U c #4B4B45459E9E", +"Y c #4C4C46469F9F", +"T c #4A4A44449B9B", +"R c #4A4A44449A9A", +"E c #494943439797", +"W c #494944449797", +"Q c #484843439494", +"! c #78787474B8B8", +"~ c #272724247878", +"^ c #2D2D2A2A7575", +"/ c #484844449797", +"( c #474743439393", +") c #454542429090", +"_ c #4B4B48489A9A", +"` c #464643438F8F", +"' c #464643438E8E", +"] c #454542428C8C", +"[ c #51514D4DA0A0", +"{ c #5C5C5959A5A5", +"} c #535350509090", +"| c #C8C8C7C7E3E3", +" . c #121211115D5D", +".. c #1A1A19196565", +"X. c #242422226D6D", +"o. c #3F3F3E3E8888", +"O. c #444442428D8D", +"+. c #444442428989", +"@. c #424241418787", +"#. c #454543438A8A", +"$. c #434342428888", +"%. c #424241418686", +"&. c #414140408484", +"*. c #414140408383", +"=. c #424240408383", +"-. c #414140408282", +";. c #474746468D8D", +":. c #464644448989", +">. c #525251519999", +",. c #64646363AAAA", +"<. c #61615F5FA2A2", +"1. c #6E6E6C6CB2B2", +"2. c #A5A5A4A4D3D3", +"3. c #B0B0AFAFD6D6", +"4. c #111112125D5D", +"5. c #19191A1A6565", +"6. c #1E1E1E1E6C6C", +"7. c #222222226D6D", +"8. c #2B2B2B2B7676", +"9. c #2B2B2B2B7575", +"0. c #2B2B2C2C7575", +"q. c #343435357F7F", +"w. c #343435357E7E", +"e. c #353535357F7F", +"r. c #3E3E3E3E8888", +"t. c #3E3E3E3E8787", +"y. c #414141418484", +"u. c #404040408282", +"i. c #484849499191", +"p. c #494949499191", +"a. c #484848489090", +"s. c #484849499090", +"d. c #404040408080", +"f. c #525252529A9A", +"g. c #525252529999", +"h. c #5B5B5B5BA3A3", +"j. c #5B5B5B5BA2A2", +"k. c #64646464ABAB", +"l. c #63636464AAAA", +"z. c #6B6B6C6CB2B2", +"x. c #72727373B9B9", +"c. c #71717171A4A4", +"v. c #78787878ABAB", +"b. c #7F7F7F7FB1B1", +"n. c #8C8C8C8CBEBE", +"m. c #A5A5A5A5D2D2", +"M. c #C9C9C9C9E5E5", +"N. c #85858686B7B7", +"B. c #91919292C4C4", +"V. c #71718989BCBC", +"C. c #73738B8BBEBE", +"Z. c #75758D8DC0C0", +"A. c #78789090C3C3", +"S. c #7A7A9292C5C5", +"D. c #71718A8ABDBD", +"F. c #76768E8EC0C0", +"G. c #78789090C2C2", +"H. c #7B7B9393C5C5", +"J. c #7D7D9595C7C7", +"K. c #80809999CACA", +"L. c #7E7E9696C7C7", +"P. c #83839B9BCDCD", +"I. c #83839B9BCCCC", +"U. c #86869E9ECFCF", +"Y. c #8888A1A1D1D1", +"T. c #8A8AA2A2D3D3", +"R. c #8989A1A1D1D1", +"E. c #8B8BA3A3D3D3", +"W. c gray100", +"Q. c black", +"!. c black", +"~. c black", +"^. c black", +"/. c black", +"(. c black", +"). c black", +"_. c black", +"`. c black", +"'. c black", +"]. c black", +"[. c black", +"{. c black", +"}. c black", +"|. c black", +" X c black", +".X c black", +"XX c black", +"oX c black", +"OX c black", +"+X c black", +"@X c black", +"#X c black", +"$X c black", +"%X c black", +"&X c black", +"*X c black", +"=X c black", +"-X c black", +";X c black", +":X c black", +">X c black", +",X c black", +"<X c black", +"1X c black", +"2X c black", +"3X c black", +"4X c black", +"5X c black", +"6X c black", +"7X c black", +"8X c black", +"9X c black", +"0X c black", +"qX c black", +"wX c black", +"eX c black", +"rX c black", +"tX c black", +"yX c black", +"uX c black", +"iX c black", +"pX c black", +"aX c black", +"sX c black", +"dX c black", +"fX c black", +"gX c black", +"hX c black", +"jX c black", +"kX c black", +"lX c black", +"zX c black", +"xX c black", +"cX c black", +"vX c black", +"bX c black", +"nX c black", +"mX c black", +"MX c black", +"NX c black", +"BX c black", +"VX c black", +"CX c black", +"ZX c black", +"AX c black", +"SX c black", +"DX c black", +"FX c black", +"GX c black", +"HX c black", +"JX c black", +"KX c black", +"LX c black", +"PX c black", +"IX c black", +"UX c black", +"YX c None", +/* pixels */ +"YXq q q q q q q q q q q q q q YX", +"q d.-.y.%.+.O.` ( E R U D C B p.", +"q u.*.&.$.#.] ) Q W T F L V M p.", +"q =.y.} , % ; 8 ! 1.{ [ S Z b p.", +"q @.:.- o 4 2.x.z.,.j.>._ A m p.", +"q +.: X < M.m.z.l.j.g.s.r.K v p.", +"q ' $ + 9 | 3.B.n.N.b.v.c.<.n p.", +"q ` O T.Y.U.P.K.L.S.G.F.C.D.l p.", +"q ( # @ G k.h.g.i.t.e.9.7.6.z p.", +"q / * E.R.U.I.K.J.H.A.Z.C.V.a p.", +"q T 2 & 5 f.a.o.q.8.7...4.J u p.", +"q I Y 1 = 7 ;.w.0.7.5. .H f y p.", +"q L D P 6 > 3 0 ^ X.~ J i t d p.", +"q C C V A N M m n p k g y r e p.", +"q M b M m m c x p j h y d s w p.", +"YXp.p.p.p.p.p.p.p.p.p.p.p.p.p.YX" +}; diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc Binary files differnew file mode 100755 index 0000000000..b88ff49e8e --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc.ini b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc.ini new file mode 100644 index 0000000000..cfa715e5a8 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/solaris-gtk-sparc/qpidmc.ini @@ -0,0 +1,40 @@ +############################################################################### +# 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. +############################################################################### +-startup +plugins/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar +--launcher.library +plugins/org.eclipse.equinox.launcher.gtk.solaris.sparc_1.0.101.R34x_v20080731 +-vmargs +-Xms40m +-Xmx256m +-XX:MaxPermSize=256m +-Dosgi.requiredJavaVersion=1.5 +-Declipse.consoleLog=true + +#=============================================== +# SSL trust store configuration options. +#=============================================== + +# Uncomment lines below to specify custom truststore for server SSL +# certificate verification, eg when using self-signed server certs. +# +#-Djavax.net.ssl.trustStore=<path.to.truststore> +#-Djavax.net.ssl.trustStorePassword=<truststore.password> + + diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/Configuration/config.ini b/qpid/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/Configuration/config.ini new file mode 100644 index 0000000000..a61bea2fa8 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/Configuration/config.ini @@ -0,0 +1,49 @@ +###############################################################################
+# 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.
+###############################################################################
+
+#Product Runtime Configuration File
+
+osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui
+eclipse.product=org.apache.qpid.management.ui.product
+osgi.bundles.defaultStartLevel=4
+osgi.bundles=jmxremote.sasl, \
+qpid-management-common, \
+org.apache.qpid.management.ui, \
+com.ibm.icu, \
+org.eclipse.core.commands, \
+org.eclipse.core.contenttype, \
+org.eclipse.core.databinding, \
+org.eclipse.core.expressions, \
+org.eclipse.core.jobs, \
+org.eclipse.core.runtime@start, \
+org.eclipse.core.runtime.compatibility.registry, \
+org.eclipse.equinox.app,org.eclipse.equinox.common, \
+org.eclipse.equinox.preferences, \
+org.eclipse.equinox.registry, \
+org.eclipse.help, \
+org.eclipse.jface, \
+org.eclipse.jface.databinding, \
+org.eclipse.swt, \
+org.eclipse.swt.win32.win32.x86, \
+org.eclipse.ui, \
+org.eclipse.ui.forms, \
+org.eclipse.ui.workbench, \
+org.eclipse.equinox.launcher, \
+org.eclipse.equinox.launcher.win32.win32.x86, \ +org.apache.commons.codec
diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.exe b/qpid/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.exe Binary files differnew file mode 100644 index 0000000000..3999884bfb --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.exe diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.ini b/qpid/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.ini new file mode 100644 index 0000000000..312580769e --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/win32-win32-x86/qpidmc.ini @@ -0,0 +1,36 @@ +###############################################################################
+# 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.
+###############################################################################
+
+-vmargs
+-Xms40m
+-Xmx256m
+-XX:MaxPermSize=256m
+-Dosgi.requiredJavaVersion=1.5
+-Declipse.consoleLog=true
+
+#===============================================
+# SSL trust store configuration options.
+#===============================================
+
+# Uncomment lines below to specify custom truststore for server SSL
+# certificate verification, eg when using self-signed server certs.
+#
+#-Djavax.net.ssl.trustStore=<path.to.truststore>
+#-Djavax.net.ssl.trustStorePassword=<truststore.password>
+
|