/* * Copyright 2011-2012 Amazon Technologies, Inc. * * Licensed 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://aws.amazon.com/apache2.0 * * This file 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 com.amazonaws.eclipse.explorer.sqs; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.ALL; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.ARN; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.CREATED; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.DELAY_SECONDS; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.MAX_MESSAGE_SIZE; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.NUMBER_OF_MESSAGES; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.RETENTION_PERIOD; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.SENDER_ID; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.SENT; import static com.amazonaws.eclipse.explorer.sqs.QueueAttributes.VISIBILITY_TIMEOUT; import java.text.DateFormat; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.TreeColumnLayout; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreePathContentProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; 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.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.forms.IFormColors; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.part.EditorPart; import com.amazonaws.eclipse.core.AWSClientFactory; import com.amazonaws.eclipse.core.AwsToolkitCore; import com.amazonaws.eclipse.core.ui.IRefreshable; import com.amazonaws.services.sqs.AmazonSQS; import com.amazonaws.services.sqs.model.DeleteMessageRequest; import com.amazonaws.services.sqs.model.GetQueueAttributesRequest; import com.amazonaws.services.sqs.model.Message; import com.amazonaws.services.sqs.model.ReceiveMessageRequest; public class QueueEditor extends EditorPart implements IRefreshable { private QueueEditorInput queueEditorInput; private Label retentionPeriodLabel; private Label maxMessageSizeLabel; private Label createdLabel; private Label visibilityTimeoutLabel; private Label queueArnLabel; private Label numberOfMessagesLabel; private TreeViewer viewer; private Label queueDelayLabel; @Override public void doSave(IProgressMonitor arg0) {} @Override public void doSaveAs() {} @Override public void setFocus() {} @Override public boolean isDirty() { return false; } @Override public boolean isSaveAsAllowed() { return false; } @Override public void init(IEditorSite site, IEditorInput input) throws PartInitException { setSite(site); setInput(input); setPartName(input.getName()); queueEditorInput = (QueueEditorInput)input; } @Override public void createPartControl(Composite parent) { FormToolkit toolkit = new FormToolkit(Display.getDefault()); ScrolledForm form = new ScrolledForm(parent, SWT.V_SCROLL); form.setExpandHorizontal(true); form.setExpandVertical(true); form.setBackground(toolkit.getColors().getBackground()); form.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); form.setFont(JFaceResources.getHeaderFont()); form.setText(queueEditorInput.getName()); toolkit.decorateFormHeading(form.getForm()); form.setImage(AwsToolkitCore.getDefault().getImageRegistry().get(AwsToolkitCore.IMAGE_QUEUE)); form.getBody().setLayout(new GridLayout()); createQueueSummaryInfoSection(form, toolkit); createMessageList(form, toolkit); form.getToolBarManager().add(new RefreshAction()); form.getToolBarManager().add(new Separator()); form.getToolBarManager().add(new AddMessageAction(getClient(), queueEditorInput.getQueueUrl(), this)); form.getToolBarManager().update(true); } private class DeleteMessageAction extends Action { public DeleteMessageAction() { this.setText("Delete"); this.setToolTipText("Delete this message from the queue"); this.setImageDescriptor(AwsToolkitCore.getDefault().getImageRegistry().getDescriptor(AwsToolkitCore.IMAGE_REMOVE)); } @Override public boolean isEnabled() { return !viewer.getSelection().isEmpty(); } @Override public void run() { StructuredSelection selection = (StructuredSelection)viewer.getSelection(); Iterator<Message> iterator = (Iterator<Message>)selection.iterator(); while (iterator.hasNext()) { Message message = iterator.next(); getClient().deleteMessage(new DeleteMessageRequest(queueEditorInput.getQueueUrl(), message.getReceiptHandle())); } new RefreshAction().run(); } } private class RefreshAction extends Action { public RefreshAction() { this.setText("Refresh"); this.setToolTipText("Refresh queue message sampling"); this.setImageDescriptor(AwsToolkitCore.getDefault().getImageRegistry().getDescriptor(AwsToolkitCore.IMAGE_REFRESH)); } @Override public void run() { new LoadMessagesThread().start(); new LoadQueueAttributesThread().start(); } } private void createQueueSummaryInfoSection(final ScrolledForm form, final FormToolkit toolkit) { GridDataFactory gridDataFactory = GridDataFactory.swtDefaults().align(SWT.FILL, SWT.TOP).grab(true, false).minSize(200, SWT.DEFAULT).hint(200, SWT.DEFAULT); Composite composite = toolkit.createComposite(form.getBody()); composite.setLayout(new GridLayout(2, false)); composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); toolkit.createLabel(composite, "Retention Period:"); retentionPeriodLabel = toolkit.createLabel(composite, ""); gridDataFactory.applyTo(retentionPeriodLabel); toolkit.createLabel(composite, "Max Message Size:", SWT.BORDER); maxMessageSizeLabel = toolkit.createLabel(composite, "", SWT.BORDER); gridDataFactory.applyTo(maxMessageSizeLabel); toolkit.createLabel(composite, "Created:"); createdLabel = toolkit.createLabel(composite, ""); gridDataFactory.applyTo(createdLabel); toolkit.createLabel(composite, "Visibility Timeout:"); visibilityTimeoutLabel = toolkit.createLabel(composite, ""); gridDataFactory.applyTo(visibilityTimeoutLabel); toolkit.createLabel(composite, "Queue ARN:"); queueArnLabel = toolkit.createLabel(composite, ""); gridDataFactory.applyTo(queueArnLabel); toolkit.createLabel(composite, "Approx. Message Count:"); numberOfMessagesLabel = toolkit.createLabel(composite, ""); gridDataFactory.applyTo(numberOfMessagesLabel); toolkit.createLabel(composite, "Message Delay (seconds):"); queueDelayLabel = toolkit.createLabel(composite, ""); gridDataFactory.applyTo(queueDelayLabel); new LoadQueueAttributesThread().start(); } private AmazonSQS getClient() { AWSClientFactory clientFactory = AwsToolkitCore.getClientFactory(queueEditorInput.getAccountId()); return clientFactory.getSQSClientByEndpoint(queueEditorInput.getRegionEndpoint()); } private class LoadQueueAttributesThread extends Thread { @Override public void run() { GetQueueAttributesRequest request = new GetQueueAttributesRequest(queueEditorInput.getQueueUrl()).withAttributeNames(ALL); final Map<String, String> attributes = getClient().getQueueAttributes(request).getAttributes(); Display.getDefault().asyncExec(new Runnable() { public void run() { retentionPeriodLabel.setText(attributes.get(RETENTION_PERIOD)); maxMessageSizeLabel.setText(attributes.get(MAX_MESSAGE_SIZE)); createdLabel.setText(attributes.get(CREATED)); visibilityTimeoutLabel.setText(attributes.get(VISIBILITY_TIMEOUT)); queueArnLabel.setText(attributes.get(ARN)); numberOfMessagesLabel.setText(attributes.get(NUMBER_OF_MESSAGES)); queueDelayLabel.setText(valueOrDefault(attributes.get(DELAY_SECONDS), "0")); numberOfMessagesLabel.getParent().layout(); } }); } private String valueOrDefault(String value, String defaultValue) { if (value != null) return value; else return defaultValue; } } private class LoadMessagesThread extends Thread { @Override public void run() { final Map<String, Message> messagesById = new HashMap<String, Message>(); for (int i = 0; i < 5; i++) { ReceiveMessageRequest request = new ReceiveMessageRequest(queueEditorInput.getQueueUrl()).withVisibilityTimeout(0).withMaxNumberOfMessages(10).withAttributeNames(ALL); List<Message> messages = getClient().receiveMessage(request).getMessages(); for (Message message : messages) { messagesById.put(message.getMessageId(), message); } } Display.getDefault().asyncExec(new Runnable() { public void run() { viewer.setInput(messagesById.values()); } }); } } private final class MessageContentProvider implements ITreePathContentProvider { private Message[] messages; public void dispose() {} public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { if (newInput instanceof Collection) { messages = ((Collection<Message>)newInput).toArray(new Message[0]); } else { messages = new Message[0]; } } public Object[] getChildren(TreePath arg0) { return null; } public Object[] getElements(Object arg0) { return messages; } public TreePath[] getParents(Object arg0) { return new TreePath[0]; } public boolean hasChildren(TreePath arg0) { return false; } } private final class MessageLabelProvider implements ITableLabelProvider { private final DateFormat dateFormat; public MessageLabelProvider() { dateFormat = DateFormat.getDateTimeInstance(); } public void addListener(ILabelProviderListener arg0) {} public void removeListener(ILabelProviderListener arg0) {} public void dispose() {} public boolean isLabelProperty(Object obj, String column) { return false; } public Image getColumnImage(Object obj, int column) { return null; } public String getColumnText(Object obj, int column) { if (obj instanceof Message == false) return ""; Message message = (Message)obj; Map<String, String> attributes = message.getAttributes(); switch (column) { case 0: return message.getMessageId(); case 1: return message.getBody(); case 2: return formatDate(attributes.get(SENT)); case 3: return attributes.get(SENDER_ID); } return ""; } private String formatDate(String epochString) { if (epochString == null || epochString.trim().length() == 0) return ""; long epochSeconds = Long.parseLong(epochString); return dateFormat.format(new Date(epochSeconds)); } } private void createMessageList(final ScrolledForm form, final FormToolkit toolkit) { Composite parent = toolkit.createComposite(form.getBody()); parent.setLayout(new GridLayout()); parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Label label = toolkit.createLabel(parent, "Message Sampling"); label.setFont(JFaceResources.getHeaderFont()); label.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); label.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false)); Composite composite = toolkit.createComposite(parent); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); TreeColumnLayout tableColumnLayout = new TreeColumnLayout(); composite.setLayout(tableColumnLayout); MessageContentProvider contentProvider = new MessageContentProvider(); MessageLabelProvider labelProvider = new MessageLabelProvider(); viewer = new TreeViewer(composite, SWT.BORDER | SWT.MULTI); viewer.getTree().setLinesVisible(true); viewer.getTree().setHeaderVisible(true); viewer.setLabelProvider(labelProvider); viewer.setContentProvider(contentProvider); createColumns(tableColumnLayout, viewer.getTree()); viewer.setInput(new Object()); MenuManager menuManager = new MenuManager(); menuManager.setRemoveAllWhenShown(true); menuManager.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { manager.add(new DeleteMessageAction()); } }); Menu menu = menuManager.createContextMenu(viewer.getTree()); viewer.getTree().setMenu(menu); getSite().registerContextMenu(menuManager, viewer); new LoadMessagesThread().start(); } private void createColumns(TreeColumnLayout columnLayout, Tree tree) { createColumn(tree, columnLayout, "ID"); createColumn(tree, columnLayout, "Body"); createColumn(tree, columnLayout, "Sent"); createColumn(tree, columnLayout, "Sender"); } private TreeColumn createColumn(Tree tree, TreeColumnLayout columnLayout, String text) { TreeColumn column = new TreeColumn(tree, SWT.NONE); column.setText(text); column.setMoveable(true); columnLayout.setColumnData(column, new ColumnWeightData(30)); return column; } public void refreshData() { new RefreshAction().run(); } }