/*******************************************************************************
* Copyright (c) 2012 - 2013 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package com.vmware.vfabric.ide.eclipse.tcserver.livegraph;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
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.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.Display;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
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 org.springframework.ide.eclipse.beans.ui.livegraph.model.LiveBeansModel;
import org.springframework.ide.eclipse.beans.ui.livegraph.model.LiveBeansModelGenerator;
import org.springframework.ide.eclipse.beans.ui.livegraph.views.LiveBeansGraphView;
import org.springsource.ide.eclipse.commons.core.StatusHandler;
import com.vmware.vfabric.ide.eclipse.tcserver.internal.core.JmxCredentials;
import com.vmware.vfabric.ide.eclipse.tcserver.internal.core.JmxUtils;
import com.vmware.vfabric.ide.eclipse.tcserver.internal.core.TcServer;
import com.vmware.vfabric.ide.eclipse.tcserver.internal.core.TcServerBehaviour;
/**
* @author Leo Dos Santos
*/
public class LiveBeansGraphEditorSection extends ServerEditorSection {
private TcServer serverWorkingCopy;
private TcServerBehaviour behaviour;
private PropertyChangeListener propertyListener;
private IServerListener stateListener;
private Button enableMbeanButton;
private Table appsTable;
private TableViewer appsViewer;
private ListApplicationsCommand listCommand;
private void addPropertyChangeListener() {
propertyListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (TcServer.PROPERTY_ADD_EXTRA_VMARGS.equals(evt.getPropertyName())) {
updateMbeanButton();
}
}
};
server.addPropertyChangeListener(propertyListener);
}
private void addServerStateListener() {
stateListener = new IServerListener() {
public void serverChanged(ServerEvent event) {
if ((event.getKind() & ServerEvent.STATE_CHANGE) != 0) {
if (event.getState() == IServer.STATE_STARTED) {
setTableState(true);
updateTableInput();
}
else if (event.getState() == IServer.STATE_STOPPED) {
setTableState(false);
updateTableInput();
}
}
else if ((event.getKind() & ServerEvent.SERVER_CHANGE) != 0) {
updateTableInput();
}
}
};
server.getOriginal().addServerListener(stateListener);
}
private void connectToApplication(String appName) {
try {
String username = null;
String password = null;
String serviceUrl = JmxUtils.getJmxUrl(behaviour);
JmxCredentials credentials = JmxUtils.getJmxCredentials(behaviour);
if (credentials != null) {
username = credentials.getUsername();
password = credentials.getPassword();
}
LiveBeansModel model = LiveBeansModelGenerator.connectToModel(serviceUrl, username, password, appName);
IViewPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.showView(LiveBeansGraphView.VIEW_ID);
if (part instanceof LiveBeansGraphView) {
((LiveBeansGraphView) part).setInput(model);
}
}
catch (PartInitException e) {
Status status = new Status(IStatus.INFO, TcServerLiveGraphPlugin.PLUGIN_ID,
"An error occurred while opening the Live Beans Graph View.", e);
openErrorDialogWithStatus(status);
}
catch (IOException e) {
Status status = new Status(IStatus.INFO, TcServerLiveGraphPlugin.PLUGIN_ID, e.getMessage(), e);
openErrorDialogWithStatus(status);
}
catch (CoreException e) {
Status status = new Status(IStatus.INFO, TcServerLiveGraphPlugin.PLUGIN_ID, e.getMessage(), e);
openErrorDialogWithStatus(status);
}
}
@Override
public void createSection(Composite parent) {
super.createSection(parent);
FormToolkit toolkit = getFormToolkit(parent.getDisplay());
Section section = toolkit.createSection(parent, ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED
| ExpandableComposite.TITLE_BAR | Section.DESCRIPTION | ExpandableComposite.FOCUS_TITLE);
section.setText("Live Beans Graph");
section.setDescription("Enable and launch the Live Beans Graph for deployed applications.");
section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL));
Composite composite = toolkit.createComposite(section);
GridLayout layout = new GridLayout();
layout.marginHeight = 5;
layout.marginWidth = 1;
layout.verticalSpacing = 5;
layout.horizontalSpacing = 10;
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL));
toolkit.paintBordersFor(composite);
section.setClient(composite);
enableMbeanButton = toolkit.createButton(composite,
"Enable Live Beans indexing (takes effect upon server restart)", SWT.CHECK);
enableMbeanButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
execute(new ModifyLiveGraphVmArgsCommand(serverWorkingCopy, enableMbeanButton.getSelection()));
}
});
GridDataFactory.fillDefaults().grab(true, false).applyTo(enableMbeanButton);
toolkit.createLabel(composite, "Double-click to view application (requires Spring 3.2):");
appsTable = toolkit.createTable(composite, SWT.SINGLE | SWT.V_SCROLL | SWT.FULL_SELECTION);
GridData data = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
data.heightHint = 90;
appsTable.setLayoutData(data);
appsViewer = new TableViewer(appsTable);
appsViewer.setContentProvider(new LiveBeansTableContentProvider());
appsViewer.setLabelProvider(new LiveBeansTableLabelProvider(server.getOriginal()));
appsViewer.setSorter(new ViewerSorter());
appsViewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
if (event.getSelection() instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
if (selection.getFirstElement() instanceof DeployedApplication) {
DeployedApplication application = (DeployedApplication) selection.getFirstElement();
if (application.isLiveBeansEnabled()) {
connectToApplication(application.getName());
}
}
}
}
});
initializeUiState();
}
@Override
public void dispose() {
if (server != null) {
server.removePropertyChangeListener(propertyListener);
server.getOriginal().removeServerListener(stateListener);
}
super.dispose();
}
@Override
public void init(IEditorSite site, IEditorInput input) {
super.init(site, input);
serverWorkingCopy = (TcServer) server.loadAdapter(TcServer.class, null);
behaviour = (TcServerBehaviour) serverWorkingCopy.getServer().loadAdapter(TcServerBehaviour.class, null);
listCommand = new ListApplicationsCommand(behaviour, false);
addPropertyChangeListener();
addServerStateListener();
initializeUiState();
}
private void initializeUiState() {
setTableState(server.getOriginal().getServerState() == IServer.STATE_STARTED);
updateTableInput();
updateMbeanButton();
}
private void openErrorDialogWithStatus(IStatus status) {
ErrorDialog.openError(getShell(), "Connection Failed", "Could not connect to the server or application.\n\n"
+ "Please ensure that the server is configured for JMX access. "
+ "This feature is only supported for applications on Spring Framework 3.2 or greater.\n\n"
+ "See the Error Log for more details.", status);
StatusHandler.log(status);
}
private void setTableState(final boolean enabled) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if (appsTable != null && !appsTable.isDisposed()) {
appsTable.setEnabled(enabled);
}
}
});
}
private void updateMbeanButton() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if (enableMbeanButton != null && !enableMbeanButton.isDisposed()) {
enableMbeanButton.setSelection(serverWorkingCopy.getAddExtraVmArgs().containsAll(
Arrays.asList(TcServerLiveGraphPlugin.FLAG_LIVE_BEANS)));
}
}
});
}
private void updateTableInput() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
Set input = Collections.EMPTY_SET;
try {
input = listCommand.execute();
}
catch (TimeoutException e1) {
// ignore, server may not be running
}
catch (CoreException e1) {
// ignore, server may not be running
}
if (appsViewer != null && appsViewer.getControl() != null && !appsViewer.getControl().isDisposed()) {
appsViewer.setInput(input);
appsViewer.refresh();
}
}
});
}
}