package rocks.inspectit.ui.rcp.ci.form.part;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
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.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormText;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
import rocks.inspectit.shared.cs.ci.assignment.AbstractClassSensorAssignment;
import rocks.inspectit.shared.cs.ci.assignment.impl.MethodSensorAssignment;
import rocks.inspectit.ui.rcp.InspectIT;
import rocks.inspectit.ui.rcp.InspectITImages;
import rocks.inspectit.ui.rcp.ci.listener.IDetailsModifiedListener;
import rocks.inspectit.ui.rcp.validation.AbstractValidationManager;
import rocks.inspectit.ui.rcp.validation.ValidationControlDecoration;
import rocks.inspectit.ui.rcp.validation.validator.FqnWildcardValidator;
/**
* The details page for the {@link MethodSensorAssignment}.
*
* @author Ivan Senic
*
*/
public class MethodSensorAssignmentDetailsPage extends AbstractClassSensorAssignmentDetailsPage<AbstractClassSensorAssignment<?>> {
/**
* Element being displayed.
*/
private MethodSensorAssignment assignment;
/**
* List of parameters.
*/
private final List<String> parametersList = new ArrayList<>();
/**
* Text box for the method name.
*/
private Text methodText;
/**
* Selection for the method.
*/
private Button methodButton;
/**
* Selection for the constructor.
*/
private Button constructorButton;
/**
* Table viewer for the parameters of the method.
*/
private TableViewer parametersTableViewer;
/**
* Selection to include only methods with specified parameters.
*/
private Button parametersButton;
/**
* Add parameter button.
*/
private Button addParameterButton;
/**
* Remove selected parameter(s) button.
*/
private Button removeParameterButton;
/**
* Selection for public modifier.
*/
private Button publicButton;
/**
* Selection for protected modifier.
*/
private Button protectedButton;
/**
* Selection for private modifier.
*/
private Button privateButton;
/**
* Selection for default modifier.
*/
private Button defaultButton;
/**
* Constructor.
*
* @param detailsModifiedListener
* listener to inform the master block on changes to the input
* @param validationManager
* validation manager of the master part
* @param canEdit
* If the data can be edited.
*/
public MethodSensorAssignmentDetailsPage(IDetailsModifiedListener<AbstractClassSensorAssignment<?>> detailsModifiedListener,
AbstractValidationManager<AbstractClassSensorAssignment<?>> validationManager, boolean canEdit) {
super(detailsModifiedListener, validationManager, canEdit);
}
/**
* @return Returns currently displayed {@link MethodSensorAssignment} or <code>null</code> if
* one does not exists.
*/
@Override
protected MethodSensorAssignment getInput() {
return assignment;
}
/**
* {@inheritDoc}
*/
@Override
public void createContents(Composite parent) {
this.createContents(parent, true);
}
/**
* Creates content. Boolean finish defines the content should be finished by adding the
* OK/cancel buttons.
*
* @param parent
* Parent composite
* @param finish
* Defines the content should be finished by adding the OK/cancel buttons.
*/
protected void createContents(Composite parent, boolean finish) {
TableWrapLayout parentLayout = new TableWrapLayout();
parentLayout.topMargin = 5;
parentLayout.leftMargin = 5;
parentLayout.rightMargin = 2;
parentLayout.bottomMargin = 2;
parentLayout.numColumns = 2;
parentLayout.makeColumnsEqualWidth = true;
parent.setLayout(parentLayout);
FormToolkit toolkit = managedForm.getToolkit();
// title
FormText title = createTitle(parent, toolkit);
TableWrapData twd = new TableWrapData(TableWrapData.FILL, TableWrapData.TOP);
twd.colspan = 2;
title.setLayoutData(twd);
// section
Section section = toolkit.createSection(parent, ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED);
section.setText("Method definition");
section.marginWidth = 10;
section.marginHeight = 5;
TableWrapData td = new TableWrapData(TableWrapData.FILL, TableWrapData.TOP);
td.grabHorizontal = true;
section.setLayoutData(td);
// main composite
Composite mainComposite = toolkit.createComposite(section);
GridLayout layout = new GridLayout(7, false);
layout.marginHeight = 5;
layout.marginWidth = 5;
layout.horizontalSpacing = 10;
mainComposite.setLayout(layout);
section.setClient(mainComposite);
addClassContents(mainComposite);
addMethodContents(mainComposite);
if (finish) {
// create help to correctly layout
twd = new TableWrapData();
twd.grabHorizontal = true;
toolkit.createLabel(parent, "", SWT.NONE).setLayoutData(twd);
}
if (!isCanEdit()) {
setEnabled(mainComposite, false);
}
}
/**
* Adds content related to class.
*
* @param mainComposite
* Composite to create on.
*/
protected void addMethodContents(Composite mainComposite) {
FormToolkit toolkit = managedForm.getToolkit();
// method name
// first row
toolkit.createLabel(mainComposite, "Method:");
methodButton = toolkit.createButton(mainComposite, "Method name", SWT.RADIO);
methodButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
methodText = toolkit.createText(mainComposite, "", SWT.BORDER);
methodText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
toolkit.createLabel(mainComposite, "");
createInfoLabel(mainComposite, toolkit, "The name of the method to be monitored. The wild-card * can be used to match any length of characters.");
// second row
toolkit.createLabel(mainComposite, "");
constructorButton = toolkit.createButton(mainComposite, "Constructor", SWT.RADIO);
constructorButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
toolkit.createLabel(mainComposite, "").setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 4, 1));
// method name validation
final ValidationControlDecoration<Text> methodValidationDecoration = new ValidationControlDecoration<Text>(methodText, this) {
@Override
protected boolean validate(Text control) {
return StringUtils.isNotEmpty(control.getText());
}
};
methodValidationDecoration.setDescriptionText("Method name must not be empty. Use wildcard * to match any method.");
methodValidationDecoration.registerListener(SWT.Modify);
addValidationControlDecoration(methodValidationDecoration);
// listeners
SelectionAdapter methodConstructorListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
methodText.setEnabled(methodButton.getSelection());
if (!methodButton.getSelection()) {
methodText.setText("");
}
methodValidationDecoration.executeValidation();
}
};
methodButton.addSelectionListener(methodConstructorListener);
constructorButton.addSelectionListener(methodConstructorListener);
// parameters
// first row
toolkit.createLabel(mainComposite, "Parameters:");
parametersButton = toolkit.createButton(mainComposite, "Only method/constructor with selected parameters", SWT.CHECK);
parametersButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 4, 1));
toolkit.createLabel(mainComposite, "");
createInfoLabel(mainComposite, toolkit,
"Restriction of the method or constructor. Only the method/constructor with specified fully qualified parameter names is monitored. For primitive type parameters use primitive names like boolean, int, long, etc. Use wildcard * to match any parameter.");
// second row
toolkit.createLabel(mainComposite, "");
// table
final Table parametersTable = toolkit.createTable(mainComposite, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL);
GridData parametersGridData = new GridData(SWT.FILL, SWT.FILL, false, false, 4, 1);
parametersGridData.heightHint = 120;
parametersTable.setLayoutData(parametersGridData);
parametersTable.setHeaderVisible(true);
// table viewer
parametersTableViewer = new TableViewer(parametersTable);
parametersTableViewer.setContentProvider(new ArrayContentProvider());
parametersTableViewer.setInput(parametersList);
createColumnsForParametersTable();
Composite parametersComposite = toolkit.createComposite(mainComposite);
parametersComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
parametersComposite.setLayout(new FillLayout(SWT.VERTICAL));
addParameterButton = toolkit.createButton(parametersComposite, "", SWT.PUSH);
addParameterButton.setImage(InspectIT.getDefault().getImage(InspectITImages.IMG_ADD));
removeParameterButton = toolkit.createButton(parametersComposite, "", SWT.PUSH);
removeParameterButton.setImage(InspectIT.getDefault().getImage(InspectITImages.IMG_REMOVE));
toolkit.createLabel(mainComposite, "");
// listeners
parametersButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
boolean parametersActive = parametersButton.getSelection();
parametersTable.setEnabled(parametersActive);
addParameterButton.setEnabled(parametersActive);
removeParameterButton.setEnabled(parametersActive);
}
});
addParameterButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event event) {
InputDialog inputDialog = new InputDialog(managedForm.getForm().getShell(), "Add Parameter", "Specify fully qualified parameter name:", "", new FqnWildcardValidator(false, true));
if ((inputDialog.open() == Window.OK) && StringUtils.isNotBlank(inputDialog.getValue())) {
parametersList.add(inputDialog.getValue());
parametersTableViewer.refresh();
getMarkDirtyListener().handleEvent(event);
}
}
});
removeParameterButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event event) {
StructuredSelection selection = (StructuredSelection) parametersTableViewer.getSelection();
if (!selection.isEmpty()) {
for (Object selectedObject : selection.toArray()) {
parametersList.remove(selectedObject);
}
parametersTableViewer.refresh();
getMarkDirtyListener().handleEvent(event);
}
}
});
parametersTableViewer.getTable().addListener(SWT.MouseDoubleClick, new Listener() {
@Override
public void handleEvent(Event event) {
StructuredSelection selection = (StructuredSelection) parametersTableViewer.getSelection();
if (!selection.isEmpty()) {
String selected = (String) selection.getFirstElement();
InputDialog inputDialog = new InputDialog(managedForm.getForm().getShell(), "Edit Parameter", "Specify fully qualified parameter name:", selected, null);
if ((inputDialog.open() == Window.OK) && StringUtils.isNotBlank(inputDialog.getValue())) {
String value = inputDialog.getValue();
int index = 0;
for (int i = 0; i < parametersList.size(); i++) {
// on == because we can have same params in the list
if (selected == parametersList.get(i)) {
index = i;
break;
}
}
parametersList.remove(index);
parametersList.add(index, value);
parametersTableViewer.refresh();
getMarkDirtyListener().handleEvent(event);
}
}
}
});
// modifiers
toolkit.createLabel(mainComposite, "Method visibility:");
publicButton = toolkit.createButton(mainComposite, "public", SWT.CHECK);
publicButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
protectedButton = toolkit.createButton(mainComposite, "protected", SWT.CHECK);
protectedButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
defaultButton = toolkit.createButton(mainComposite, "default", SWT.CHECK);
defaultButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
privateButton = toolkit.createButton(mainComposite, "private", SWT.CHECK);
privateButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
toolkit.createLabel(mainComposite, "");
createInfoLabel(mainComposite, toolkit,
"The additional options of the sensor assignment can include the definition of the method/constructor visibility modifier(s) that should be instrumented. Thus, the methods can be additionally filtered by the visibility modifier that can be: public, protected, private or default");
ValidationControlDecoration<Button> modifiersControlDecoration = new ValidationControlDecoration<Button>(publicButton, null, this) {
@Override
protected boolean validate(Button control) {
return publicButton.getSelection() || protectedButton.getSelection() || defaultButton.getSelection() || privateButton.getSelection();
}
};
modifiersControlDecoration.setDescriptionText("At least one type of modifiers must be selected.");
modifiersControlDecoration.registerListener(publicButton, SWT.Selection);
modifiersControlDecoration.registerListener(protectedButton, SWT.Selection);
modifiersControlDecoration.registerListener(defaultButton, SWT.Selection);
modifiersControlDecoration.registerListener(privateButton, SWT.Selection);
addValidationControlDecoration(modifiersControlDecoration);
// dirty listener
methodButton.addListener(SWT.Selection, getMarkDirtyListener());
methodText.addListener(SWT.Modify, getMarkDirtyListener());
parametersButton.addListener(SWT.Selection, getMarkDirtyListener());
publicButton.addListener(SWT.Selection, getMarkDirtyListener());
protectedButton.addListener(SWT.Selection, getMarkDirtyListener());
defaultButton.addListener(SWT.Selection, getMarkDirtyListener());
privateButton.addListener(SWT.Selection, getMarkDirtyListener());
}
/**
* Column for the table viewer.
*/
private void createColumnsForParametersTable() {
TableViewerColumn paramColumn = new TableViewerColumn(parametersTableViewer, SWT.NONE);
paramColumn.getColumn().setResizable(true);
paramColumn.getColumn().setWidth(100);
paramColumn.getColumn().setText("Parameter FQN");
paramColumn.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
return (String) element;
}
});
paramColumn.getColumn().setToolTipText("Parameter FQN or primitive type name.");
}
/**
* {@inheritDoc}
*/
@Override
protected void updateFromInput() {
super.updateFromInput();
methodText.setEnabled(false);
methodText.setText("");
methodButton.setSelection(false);
constructorButton.setSelection(false);
parametersButton.setSelection(false);
parametersList.clear();
publicButton.setSelection(false);
protectedButton.setSelection(false);
privateButton.setSelection(false);
defaultButton.setSelection(false);
MethodSensorAssignment assignment = getInput();
if (null != assignment) {
if (assignment.isConstructor()) {
constructorButton.setSelection(true);
} else {
methodText.setEnabled(isCanEdit());
methodText.setText(StringUtils.defaultString(assignment.getMethodName()));
methodButton.setSelection(true);
}
if (null != assignment.getParameters()) {
parametersButton.setSelection(true);
parametersTableViewer.getTable().setEnabled(isCanEdit());
addParameterButton.setEnabled(isCanEdit());
removeParameterButton.setEnabled(isCanEdit());
for (String param : assignment.getParameters()) {
parametersList.add(param);
}
} else {
parametersTableViewer.getTable().setEnabled(false);
addParameterButton.setEnabled(false);
removeParameterButton.setEnabled(false);
}
publicButton.setSelection(assignment.isPublicModifier());
protectedButton.setSelection(assignment.isProtectedModifier());
privateButton.setSelection(assignment.isPrivateModifier());
defaultButton.setSelection(assignment.isDefaultModifier());
}
parametersTableViewer.refresh();
}
/**
* {@inheritDoc}
*/
@Override
protected void commitToInput() {
super.commitToInput();
MethodSensorAssignment assignment = getInput();
if (null != assignment) {
assignment.setConstructor(constructorButton.getSelection());
if (!assignment.isConstructor()) {
assignment.setMethodName(methodText.getText());
} else {
assignment.setMethodName(null);
}
if (parametersButton.getSelection()) {
assignment.setParameters(new ArrayList<>(parametersList));
} else {
assignment.setParameters(null);
}
assignment.setPublicModifier(publicButton.getSelection());
assignment.setProtectedModifier(protectedButton.getSelection());
assignment.setPrivateModifier(privateButton.getSelection());
assignment.setDefaultModifier(defaultButton.getSelection());
}
}
/**
* {@inheritDoc}
*/
@Override
protected void setInput(ISelection selection) {
if (!selection.isEmpty()) {
assignment = (MethodSensorAssignment) ((IStructuredSelection) selection).getFirstElement();
} else {
assignment = null; // NOPMD
}
}
}