/*
* Copyright 2010-2012 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. 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.elasticbeanstalk.server.ui.configEditor;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
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.layout.TreeColumnLayout;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.wst.server.core.IServer;
import org.eclipse.wst.server.core.IServerListener;
import org.eclipse.wst.server.core.ServerEvent;
import org.eclipse.wst.server.ui.editor.ServerEditorSection;
import com.amazonaws.eclipse.core.AwsToolkitCore;
import com.amazonaws.eclipse.elasticbeanstalk.ElasticBeanstalkPlugin;
import com.amazonaws.eclipse.elasticbeanstalk.Environment;
import com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalk;
import com.amazonaws.services.elasticbeanstalk.model.DescribeEventsRequest;
import com.amazonaws.services.elasticbeanstalk.model.EventDescription;
import com.amazonaws.services.elasticbeanstalk.model.EventSeverity;
/**
* Editor part which displays the event log.
*/
public class EventLogEditorSection extends ServerEditorSection {
/** The section widget we're managing */
private Section section;
private FormToolkit toolkit;
private TreeViewer viewer;
private boolean tableDataLoaded = false;
private static final Object JOB_FAMILY = new Object();
private AutoRefreshListener autoRefreshListener;
private volatile boolean disposed;
@Override
public void createSection(Composite parent) {
super.createSection(parent);
toolkit = getFormToolkit(parent.getDisplay());
section = toolkit.createSection(parent,
Section.TITLE_BAR | Section.DESCRIPTION );
section.setText("Environment Events");
section.setDescription("Events recorded to your Elastic Beanstalk environment");
Composite composite = toolkit.createComposite(section);
FillLayout layout = new FillLayout();
layout.marginHeight = 10;
layout.marginWidth = 10;
layout.type = SWT.VERTICAL;
composite.setLayout(layout);
toolkit.paintBordersFor(composite);
section.setClient(composite);
section.setLayout(layout);
createEventsTable(composite);
configureAutoRefresh();
refresh();
}
private void configureAutoRefresh() {
autoRefreshListener = new AutoRefreshListener();
Environment environment = (Environment) server.loadAdapter(Environment.class, null);
environment.getServer().addServerListener(autoRefreshListener);
// Go ahead and start auto refreshing if the server is already
// starting up, since we won't see the starting event
if (environment.getServer().getServerState() == IServer.STATE_STARTING) {
EventLogRefreshManager.getInstance().startAutoRefresh(this);
}
}
protected TreeColumn newColumn(String columnText, int weight) {
Tree table = viewer.getTree();
TreeColumn column = new TreeColumn(table, SWT.NONE);
column.setText(columnText);
TreeColumnLayout tableColumnLayout = (TreeColumnLayout) viewer.getTree().getParent().getLayout();
if ( tableColumnLayout == null ) {
tableColumnLayout = new TreeColumnLayout();
}
tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));
return column;
}
private final class AutoRefreshListener implements IServerListener {
public void serverChanged(ServerEvent event) {
if ((event.getKind() & ServerEvent.SERVER_CHANGE) == 0) {
return;
}
switch (event.getState()) {
case IServer.STATE_STARTING:
EventLogRefreshManager.getInstance().startAutoRefresh(EventLogEditorSection.this);
break;
default:
EventLogRefreshManager.getInstance().stopAutoRefresh(EventLogEditorSection.this);
break;
}
}
public void dispose() {
EventLogRefreshManager.getInstance().stopAutoRefresh(EventLogEditorSection.this);
}
}
/** Populates the Event Log context menu with actions. */
private final class EventLogMenuListener implements IMenuListener {
private Action copyToClipboardAction = new Action("Copy to Clipboard") {
@Override
public ImageDescriptor getImageDescriptor() {
return ElasticBeanstalkPlugin.getDefault().getImageRegistry().getDescriptor(ElasticBeanstalkPlugin.IMG_CLIPBOARD);
}
@Override
public void run() {
final Clipboard clipboard = new Clipboard(Display.getDefault());
String eventText = "";
for (TreeItem treeItem : viewer.getTree().getSelection()) {
if (eventText == null) {
eventText = treeItem.getData().toString();
} else {
eventText += "\n" + treeItem.getData().toString();
}
}
TextTransfer textTransfer = TextTransfer.getInstance();
clipboard.setContents(new Object[]{eventText}, new Transfer[]{textTransfer});
}
};
public void menuAboutToShow(IMenuManager manager) {
TreeItem[] selection = viewer.getTree().getSelection();
copyToClipboardAction.setEnabled(selection != null && selection.length > 0);
manager.add(copyToClipboardAction);
}
}
private class LoadEnvironmentEventsJob extends Job {
private final Environment environment;
public LoadEnvironmentEventsJob(Environment environment) {
super("Loading events for environment " + environment.getEnvironmentName());
this.environment = environment;
this.setSystem(true);
}
@Override
protected IStatus run(IProgressMonitor monitor) {
AWSElasticBeanstalk client = AwsToolkitCore.getClientFactory(environment.getAccountId())
.getElasticBeanstalkClientByEndpoint(environment.getRegionEndpoint());
final List<EventDescription> events = client.describeEvents(new DescribeEventsRequest()
.withEnvironmentName(environment.getEnvironmentName())).getEvents();
Display.getDefault().syncExec(new Runnable() {
public void run() {
if (disposed || viewer.getTree().isDisposed()) {
return;
}
// Preserve the current column widths
int[] colWidth = new int[viewer.getTree().getColumns().length];
int i = 0;
for (TreeColumn col : viewer.getTree().getColumns()) {
colWidth[i++] = col.getWidth();
}
viewer.setInput(events);
// If this is the first time loading the table data, don't
// set the column widths -- this will make them zero on
// windows.
if ( tableDataLoaded ) {
i = 0;
for ( TreeColumn col : viewer.getTree().getColumns() ) {
col.setWidth(colWidth[i++]);
}
} else {
tableDataLoaded = true;
}
}
});
return Status.OK_STATUS;
}
@Override
public boolean belongsTo(Object family) {
return family == JOB_FAMILY;
}
}
private void addContextMenu() {
MenuManager menuManager = new MenuManager("#PopupMenu");
menuManager.setRemoveAllWhenShown(true);
menuManager.addMenuListener(new EventLogMenuListener());
Menu menu = menuManager.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
}
private void createEventsTable(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
TreeColumnLayout treeColumnLayout = new TreeColumnLayout();
composite.setLayout(treeColumnLayout);
int style = SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER | SWT.MULTI;
viewer = new TreeViewer(composite, style);
viewer.getTree().setLinesVisible(true);
viewer.getTree().setHeaderVisible(true);
addContextMenu();
newColumn("Message", 75);
newColumn("Version", 10);
newColumn("Date", 15);
viewer.setContentProvider(new ITreeContentProvider() {
private List<EventDescription> events;
@SuppressWarnings("unchecked")
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
if (newInput == null) {
events = new ArrayList<EventDescription>();
} else {
events = (List<EventDescription>)newInput;
}
}
public void dispose() {
}
public Object[] getElements(Object inputElement) {
return events.toArray();
}
public Object[] getChildren(Object parentElement) {
return new Object[0];
}
public Object getParent(Object element) {
return null;
}
public boolean hasChildren(Object element) {
return false;
}
});
viewer.setLabelProvider(new ITableLabelProvider() {
public void removeListener(ILabelProviderListener listener) {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void dispose() {
}
public void addListener(ILabelProviderListener listener) {
}
public String getColumnText(Object element, int columnIndex) {
EventDescription event = (EventDescription) element;
switch (columnIndex) {
case 0:
return event.getMessage();
case 1:
return event.getVersionLabel();
case 2:
return event.getEventDate().toString();
default:
return "";
}
}
public Image getColumnImage(Object element, int columnIndex) {
if (element == null) {
return null;
}
if (columnIndex != 0) {
return null;
}
EventSeverity eventSeverity = null;
try {
EventDescription event = (EventDescription)element;
eventSeverity = EventSeverity.fromValue(event.getSeverity());
} catch (IllegalArgumentException e) {
return null;
}
switch (eventSeverity) {
case ERROR:
case FATAL:
return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK);
case WARN:
return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_WARN_TSK);
case INFO:
case DEBUG:
case TRACE:
return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_INFO_TSK);
}
return null;
}
});
}
@Override
public void dispose() {
disposed = true;
if (autoRefreshListener != null) {
Environment environment = (Environment) server.loadAdapter(Environment.class, null);
environment.getServer().removeServerListener(autoRefreshListener);
autoRefreshListener.dispose();
}
super.dispose();
}
public String getServerName() {
return server.getName();
}
/**
* Refreshes the events in the table.
*/
void refresh() {
/*
* There's a race condition here, but the consequences are trivial.
*/
if ( Job.getJobManager().find(JOB_FAMILY).length == 0 ) {
Environment environment = (Environment) server.loadAdapter(Environment.class, null);
new LoadEnvironmentEventsJob(environment).schedule();
}
}
}