diff options
Diffstat (limited to 'qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/QueueTypeTabControl.java')
-rw-r--r-- | qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/type/QueueTypeTabControl.java | 786 |
1 files changed, 786 insertions, 0 deletions
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); + } + } +} |