/* * 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.sns; import java.util.Iterator; import java.util.LinkedList; 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.dialogs.MessageDialog; 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.sns.AmazonSNS; import com.amazonaws.services.sns.model.GetTopicAttributesRequest; import com.amazonaws.services.sns.model.ListSubscriptionsByTopicRequest; import com.amazonaws.services.sns.model.ListSubscriptionsByTopicResult; import com.amazonaws.services.sns.model.Subscription; import com.amazonaws.services.sns.model.UnsubscribeRequest; public class TopicEditor extends EditorPart implements IRefreshable { private TopicEditorInput topicEditorInput; private TreeViewer viewer; private Label ownerLabel; private Label pendingSubscriptionsLabel; private Label confirmedSubscriptionsLabel; private Label deletedSubscriptionsLabel; private Label displayNameLabel; private Label topicArnLabel; @Override public void doSave(IProgressMonitor monitor) {} @Override public void doSaveAs() {} @Override public boolean isDirty() { return false; } @Override public boolean isSaveAsAllowed() { return false; } @Override public void setFocus() {} @Override public void init(IEditorSite site, IEditorInput input) throws PartInitException { setSite(site); setInput(input); setPartName(input.getName()); topicEditorInput = (TopicEditorInput)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(topicEditorInput.getName()); toolkit.decorateFormHeading(form.getForm()); form.setImage(AwsToolkitCore.getDefault().getImageRegistry().get(AwsToolkitCore.IMAGE_QUEUE)); form.getBody().setLayout(new GridLayout()); createTopicSummaryComposite(toolkit, form.getBody()); createSubscriptionsComposite(toolkit, form.getBody()); form.getToolBarManager().add(new RefreshAction()); form.getToolBarManager().add(new Separator()); form.getToolBarManager().add(new PublishMessageAction(getClient(), topicEditorInput.getTopic())); form.getToolBarManager().add(new NewSubscriptionAction(getClient(), topicEditorInput.getTopic(), this)); form.getToolBarManager().update(true); } private class LoadTopicAttributesThread extends Thread { @Override public void run() { try { GetTopicAttributesRequest request = new GetTopicAttributesRequest(topicEditorInput.getTopic().getTopicArn()); final Map<String, String> attributes = getClient().getTopicAttributes(request).getAttributes(); Display.getDefault().asyncExec(new Runnable() { public void run() { ownerLabel.setText(getValue(attributes,"Owner")); pendingSubscriptionsLabel.setText(getValue(attributes, "SubscriptionsPending")); confirmedSubscriptionsLabel.setText(getValue(attributes, "SubscriptionsConfirmed")); deletedSubscriptionsLabel.setText(getValue(attributes, "SubscriptionsDeleted")); displayNameLabel.setText(getValue(attributes, "DisplayName")); topicArnLabel.setText(getValue(attributes, "TopicArn")); } private String getValue(Map<String, String> map, String key) { if (map.get(key) != null) return map.get(key); return ""; } }); } catch (Exception e) { AwsToolkitCore.getDefault().reportException("Unable to load topic attributes", e); } } } private final class UnsubscribeAction extends Action { public UnsubscribeAction() { this.setText("Delete Subscription"); this.setToolTipText("Delete the selected subscriptions"); this.setImageDescriptor(AwsToolkitCore.getDefault().getImageRegistry().getDescriptor(AwsToolkitCore.IMAGE_REMOVE)); } @Override public boolean isEnabled() { boolean isEmpty = viewer.getSelection().isEmpty(); return !isEmpty; } @Override public void run() { MessageDialog confirmationDialog = new MessageDialog( Display.getDefault().getActiveShell(), "Delete Subscriptions?", null, "Are you sure you want to delete the selected subscriptions?", MessageDialog.QUESTION, new String[] {"OK", "Cancel"}, 0); if (confirmationDialog.open() == 0) { StructuredSelection selection = (StructuredSelection)viewer.getSelection(); Iterator<Subscription> iterator = selection.iterator(); while (iterator.hasNext()) { Subscription subscription = iterator.next(); try { getClient().unsubscribe(new UnsubscribeRequest(subscription.getSubscriptionArn())); } catch (Exception e) { AwsToolkitCore.getDefault().reportException("Unable to delete subscription", e); } } new RefreshAction().run(); } } } private final class RefreshAction extends Action { public RefreshAction() { this.setText("Refresh"); this.setToolTipText("Refresh topic information and subscriptions"); this.setImageDescriptor(AwsToolkitCore.getDefault().getImageRegistry().getDescriptor(AwsToolkitCore.IMAGE_REFRESH)); } @Override public void run() { new LoadTopicAttributesThread().start(); new LoadSubscriptionsThread().start(); } } private AmazonSNS getClient() { AWSClientFactory clientFactory = AwsToolkitCore.getClientFactory(topicEditorInput.getAccountId()); return clientFactory.getSNSClientByEndpoint(topicEditorInput.getRegionEndpoint()); } private final class SubscriptionContentProvider implements ITreePathContentProvider { private Subscription[] subscriptions; public void dispose() {} public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { if (newInput instanceof List) { subscriptions = ((List<Subscription>)newInput).toArray(new Subscription[0]); } else { subscriptions = new Subscription[0]; } } public Object[] getElements(Object inputElement) { return subscriptions; } public Object[] getChildren(TreePath parentPath) { return null; } public boolean hasChildren(TreePath path) { return false; } public TreePath[] getParents(Object element) { return null; } } private final class SubscriptionLabelProvider implements ITableLabelProvider { public void dispose() {} public void addListener(ILabelProviderListener listener) {} public void removeListener(ILabelProviderListener listener) {} public boolean isLabelProperty(Object element, String property) { return false; } public Image getColumnImage(Object element, int columnIndex) { return null; } public String getColumnText(Object element, int columnIndex) { if (element instanceof Subscription == false) return "???"; Subscription subscription = (Subscription)element; switch (columnIndex) { case 0: return subscription.getProtocol(); case 1: return subscription.getOwner(); case 2: return subscription.getEndpoint(); case 3: return subscription.getSubscriptionArn(); default: return ""; } } } private void createTopicSummaryComposite(FormToolkit toolkit, Composite parent) { GridDataFactory gdf = GridDataFactory.swtDefaults().align(SWT.FILL, SWT.TOP).grab(true, false); Composite summaryComposite = toolkit.createComposite(parent); summaryComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); summaryComposite.setLayout(new GridLayout(2, false)); toolkit.createLabel(summaryComposite, "Owner ID:"); ownerLabel = toolkit.createLabel(summaryComposite, ""); gdf.applyTo(ownerLabel); toolkit.createLabel(summaryComposite, "Pending Subscriptions:"); pendingSubscriptionsLabel = toolkit.createLabel(summaryComposite, ""); gdf.applyTo(pendingSubscriptionsLabel); toolkit.createLabel(summaryComposite, "Confirmed Subscriptions:"); confirmedSubscriptionsLabel = toolkit.createLabel(summaryComposite, ""); gdf.applyTo(confirmedSubscriptionsLabel); toolkit.createLabel(summaryComposite, "Deleted Subscriptions:"); deletedSubscriptionsLabel = toolkit.createLabel(summaryComposite, ""); gdf.applyTo(deletedSubscriptionsLabel); toolkit.createLabel(summaryComposite, "Display Name:"); displayNameLabel = toolkit.createLabel(summaryComposite, ""); gdf.applyTo(displayNameLabel); toolkit.createLabel(summaryComposite, "Topic ARN:"); topicArnLabel = toolkit.createLabel(summaryComposite, ""); gdf.applyTo(topicArnLabel); new LoadTopicAttributesThread().start(); } private void createSubscriptionsComposite(FormToolkit toolkit, Composite parent) { Composite subscriptionsComposite = toolkit.createComposite(parent); subscriptionsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); subscriptionsComposite.setLayout(new GridLayout()); Label label = toolkit.createLabel(subscriptionsComposite, "Subscriptions"); 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(subscriptionsComposite); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); TreeColumnLayout tableColumnLayout = new TreeColumnLayout(); composite.setLayout(tableColumnLayout); SubscriptionContentProvider contentProvider = new SubscriptionContentProvider(); SubscriptionLabelProvider labelProvider = new SubscriptionLabelProvider(); 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()); final IRefreshable refreshable = this; MenuManager menuManager = new MenuManager(); menuManager.setRemoveAllWhenShown(true); menuManager.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { manager.add(new NewSubscriptionAction(getClient(), topicEditorInput.getTopic(), refreshable)); manager.add(new UnsubscribeAction()); } }); Menu menu = menuManager.createContextMenu(viewer.getTree()); viewer.getTree().setMenu(menu); getSite().registerContextMenu(menuManager, viewer); refreshData(); } private void createColumns(TreeColumnLayout columnLayout, Tree tree) { createColumn(tree, columnLayout, "Protocol"); createColumn(tree, columnLayout, "Owner"); createColumn(tree, columnLayout, "Endpoint"); createColumn(tree, columnLayout, "Subscription ARN"); } 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 LoadSubscriptionsThread().start(); } private class LoadSubscriptionsThread extends Thread { @Override public void run() { AmazonSNS sns = getClient(); try { String topicArn = topicEditorInput.getTopic().getTopicArn(); String nextToken = null; ListSubscriptionsByTopicResult subscriptionsByTopic = null; final List<Subscription> subscriptions = new LinkedList<Subscription>(); do { if (subscriptionsByTopic != null) nextToken = subscriptionsByTopic.getNextToken(); subscriptionsByTopic = sns.listSubscriptionsByTopic(new ListSubscriptionsByTopicRequest(topicArn, nextToken)); subscriptions.addAll(subscriptionsByTopic.getSubscriptions()); } while (subscriptionsByTopic.getNextToken() != null); Display.getDefault().asyncExec(new Runnable() { public void run() { viewer.setInput(subscriptions); } }); } catch (Exception e) { AwsToolkitCore.getDefault().reportException("Unable to list subscriptions", e); } } } }