/* * Copyright 2008-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.ec2.ui.ebs; import java.text.DateFormat; import java.util.List; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Tree; import org.eclipse.ui.statushandlers.StatusManager; import com.amazonaws.eclipse.core.AwsToolkitCore; import com.amazonaws.eclipse.core.ui.IRefreshable; import com.amazonaws.eclipse.ec2.Ec2Plugin; import com.amazonaws.eclipse.ec2.TagFormatter; import com.amazonaws.eclipse.ec2.ui.SelectionTable; import com.amazonaws.eclipse.ec2.ui.SelectionTableComparator; import com.amazonaws.eclipse.ec2.ui.views.instances.RefreshTimer; import com.amazonaws.services.ec2.AmazonEC2; import com.amazonaws.services.ec2.model.DeleteSnapshotRequest; import com.amazonaws.services.ec2.model.Snapshot; /** * SelectionTable subclass for selecting EBS snapshots. */ public class SnapshotSelectionTable extends SelectionTable implements IRefreshable { /** The period between refreshes when snapshots are in progress */ private static final int REFRESH_PERIOD_IN_MILLISECONDS = 10 * 1000; private static final int STATE_COLUMN = 0; private static final int SNAPSHOT_ID_COLUMN = 1; private static final int VOLUME_ID_COLUMN = 2; private static final int START_TIME_COLUMN = 3; private static final int TAGS_COLUMN = 4; /** An Action implementation that refreshes the snapshots */ private Action refreshAction; /** An Action implementation that deletes the selected snapshot */ private Action deleteAction; /** * The timer we turn on when snapshots are in progress to refresh * the snapshot data. */ private RefreshTimer refreshTimer; /** * Comparator for sorting snapshots by creation time. */ class SnapshotComparator extends SelectionTableComparator { public SnapshotComparator(int defaultColumn) { super(defaultColumn); } /* (non-Javadoc) * @see com.amazonaws.eclipse.ec2.ui.SelectionTableComparator#compareIgnoringDirection(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ @Override protected int compareIgnoringDirection(Viewer viewer, Object e1, Object e2) { if (!(e1 instanceof Snapshot && e2 instanceof Snapshot)) { return 0; } Snapshot snapshot1 = (Snapshot)e1; Snapshot snapshot2 = (Snapshot)e2; switch (this.sortColumn) { case STATE_COLUMN: return snapshot1.getState().compareTo(snapshot2.getState()); case SNAPSHOT_ID_COLUMN: return snapshot1.getSnapshotId().compareTo(snapshot2.getSnapshotId()); case VOLUME_ID_COLUMN: return snapshot1.getVolumeId().compareTo(snapshot2.getVolumeId()); case START_TIME_COLUMN: return snapshot1.getStartTime().compareTo(snapshot2.getStartTime()); case TAGS_COLUMN: return TagFormatter.formatTags(snapshot1.getTags()).compareTo( TagFormatter.formatTags(snapshot2.getTags())); } return 0; } } /** * Label and content provider for snapshot selection table. */ private static class SnapshotTableProvider extends LabelProvider implements ITreeContentProvider, ITableLabelProvider { private final DateFormat dateFormat = DateFormat.getDateTimeInstance(); List<Object> snapshots; /* * IStructuredContentProvider Interface */ /* (non-Javadoc) * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) */ public Object[] getElements(Object inputElement) { if (snapshots == null) return null; return snapshots.toArray(); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ @SuppressWarnings("unchecked") public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { if (newInput instanceof List) { snapshots = (List<Object>)newInput; } } /* * ITableLabelProvider Interface */ /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) */ public Image getColumnImage(Object element, int columnIndex) { if (columnIndex == 0) return Ec2Plugin.getDefault().getImageRegistry().get("snapshot"); return null; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) */ public String getColumnText(Object element, int columnIndex) { if (!(element instanceof Snapshot)) { return "???"; } Snapshot snapshot = (Snapshot)element; switch (columnIndex) { case STATE_COLUMN: if (snapshot.getState().equalsIgnoreCase("pending")) { if (snapshot.getProgress() != null && snapshot.getProgress().length() > 0) { return "pending (" + snapshot.getProgress() + ")"; } else { return "pending"; } } return snapshot.getState(); case SNAPSHOT_ID_COLUMN: return snapshot.getSnapshotId(); case VOLUME_ID_COLUMN: return snapshot.getVolumeId(); case START_TIME_COLUMN: if (snapshot.getStartTime() == null) return ""; return dateFormat.format(snapshot.getStartTime()); case TAGS_COLUMN: return TagFormatter.formatTags(snapshot.getTags()); } return "???"; } public Object[] getChildren(Object parentElement) { return new Object[0]; } public Object getParent(Object element) { return null; } public boolean hasChildren(Object element) { return false; } } /** * Creates a new snapshot selection table with the specified parent. * * @param parent * The parent ui component for the new snapshot selection table. */ public SnapshotSelectionTable(Composite parent) { super(parent); SnapshotTableProvider snapshotTableProvider = new SnapshotTableProvider(); viewer.setContentProvider(snapshotTableProvider); viewer.setLabelProvider(snapshotTableProvider); setComparator(new SnapshotComparator(START_TIME_COLUMN)); refreshSnapshots(); refreshTimer = new RefreshTimer(this, REFRESH_PERIOD_IN_MILLISECONDS); } /** * Returns the currently selected snapshot. * * @return The currently selected snapshot. */ public Snapshot getSelectedSnapshot() { return (Snapshot)getSelection(); } /** * Refreshes the list of snapshots displayed by this snapshot selection * table. */ public void refreshSnapshots() { new RefreshSnapshotsThread().start(); } /* (non-Javadoc) * @see com.amazonaws.eclipse.ec2.ui.IRefreshable#refreshData() */ public void refreshData() { this.refreshSnapshots(); } /* * SelectionTable Interface */ /* (non-Javadoc) * @see com.amazonaws.eclipse.ec2.ui.SelectionTable#createColumns() */ @Override protected void createColumns() { newColumn("State", 10); newColumn("Snapshot ID", 10); newColumn("Volume ID", 10); newColumn("Creation Time", 60); newColumn("Tags", 15); } /* (non-Javadoc) * @see com.amazonaws.eclipse.ec2.ui.SelectionTable#fillContextMenu(org.eclipse.jface.action.IMenuManager) */ @Override protected void fillContextMenu(IMenuManager manager) { Snapshot selectedSnapshot = getSelectedSnapshot(); boolean isSnapshotSelected = (selectedSnapshot != null); deleteAction.setEnabled(isSnapshotSelected); manager.add(refreshAction); manager.add(new Separator()); manager.add(deleteAction); } /* (non-Javadoc) * @see com.amazonaws.eclipse.ec2.ui.SelectionTable#makeActions() */ @Override protected void makeActions() { refreshAction = new Action() { public void run() { refreshSnapshots(); } }; refreshAction.setText("Refresh"); refreshAction.setToolTipText("Refresh the list of snapshots."); refreshAction.setImageDescriptor(Ec2Plugin.getDefault().getImageRegistry().getDescriptor("refresh")); deleteAction = new Action () { public void run() { Snapshot selectedSnapshot = getSelectedSnapshot(); new DeleteSnapshotThread(selectedSnapshot).start(); } }; deleteAction.setText("Delete Snapshot"); deleteAction.setToolTipText("Delete the selected snapshot."); deleteAction.setImageDescriptor(Ec2Plugin.getDefault().getImageRegistry().getDescriptor("remove")); } /* * Private Interface */ /** * Sets the input of this control to the specified list of snapshots and * also takes care of any special requirements of in progress snapshots such * as turning on the refresh timer and displaying progress bars for the * snapshot progress. * * @param snapshots * The list of snapshots that should be displayed in this * selection table. */ private void setInput(final List<Snapshot> snapshots) { Display.getDefault().asyncExec(new Runnable() { public void run() { Snapshot previouslySelectedSnapshot = getSelectedSnapshot(); viewer.setInput(snapshots); packColumns(); if (previouslySelectedSnapshot != null) { Tree table = viewer.getTree(); for (int i = 0; i < table.getItemCount(); i++) { Snapshot snapshot = (Snapshot)table.getItem(i).getData(); if (snapshot.getSnapshotId().equals(previouslySelectedSnapshot.getSnapshotId())) { table.select(table.getItem(i)); } } } resetRefreshTimer(snapshots); } }); } /** * Turns on or off the refresh timer depending on whether or not any of the * specified snapshots are currently in progress. If snapshots are in * progress, the refresh timer is turned on so that the user watch as the * snapshot progresses, otherwise the refresh timer is turned off. * * @param snapshots * The snapshots being displayed by this control. */ private void resetRefreshTimer(List<Snapshot> snapshots) { for (Snapshot snapshot : snapshots) { if (snapshot.getState().equalsIgnoreCase("pending")) { refreshTimer.startTimer(); return; } } refreshTimer.stopTimer(); } /* * Private Threads for making EC2 service calls */ /** * Thread for making an EC2 service call to refresh the list of EBS * snapshots for the current account. */ private class RefreshSnapshotsThread extends Thread { /* (non-Javadoc) * @see java.lang.Thread#run() */ @Override public void run() { try { AmazonEC2 ec2 = getAwsEc2Client(); final List<Snapshot> snapshots = ec2.describeSnapshots().getSnapshots(); setInput(snapshots); } catch (Exception e) { // Only log an error if the account info is valid and we // actually expected this call to work if (AwsToolkitCore.getDefault().getAccountInfo().isValid()) { Status status = new Status(Status.ERROR, Ec2Plugin.PLUGIN_ID, "Unable to refresh snapshots: " + e.getMessage(), e); StatusManager.getManager().handle(status, StatusManager.LOG); } } } } /** * Thread for making an EC2 service call to delete a snapshot. */ private class DeleteSnapshotThread extends Thread { /** The snapshot to delete */ private final Snapshot snapshot; /** * Creates a new thread ready to be started to delete the specified * snapshot. * * @param snapshot * The snapshot to delete. */ public DeleteSnapshotThread(Snapshot snapshot) { this.snapshot = snapshot; } /* (non-Javadoc) * @see java.lang.Thread#run() */ @Override public void run() { try { getAwsEc2Client().deleteSnapshot(new DeleteSnapshotRequest() .withSnapshotId(snapshot.getSnapshotId())); refreshSnapshots(); } catch (Exception e) { Status status = new Status(Status.ERROR, Ec2Plugin.PLUGIN_ID, "Unable to delete snapshot: " + e.getMessage(), e); StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG); } } } }