/*
* Copyright 2013 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.dynamodb;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.databinding.AggregateValidationStatus;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.PojoObservables;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
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.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import com.amazonaws.eclipse.core.AwsToolkitCore;
import com.amazonaws.eclipse.databinding.ChainValidator;
import com.amazonaws.eclipse.databinding.NotEmptyValidator;
import com.amazonaws.eclipse.databinding.RangeValidator;
import com.amazonaws.eclipse.dynamodb.AbstractAddNewAttributeDialog;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.Projection;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
public class AddGSIDialog extends TitleAreaDialog {
/** Widget used as data-binding targets **/
private Text indexHashKeyNameText;
private Combo indexHashKeyAttributeTypeCombo;
private Button enableIndexRangeKeyButton;
private Text indexRangeKeyNameText;
private Combo indexRangeKeyAttributeTypeCombo;
private Text indexNameText;
private Combo projectionTypeCombo;
private Button addAttributeButton;
private Button okButton;
/** The data objects that will be used to generate the service request **/
private final GlobalSecondaryIndex globalSecondaryIndex;
private final KeySchemaElement indexRangeKeySchemaDefinition = new KeySchemaElement()
.withAttributeName(null).withKeyType(KeyType.RANGE);
private final AttributeDefinition indexHashKeyAttributeDefinition = new AttributeDefinition();
private final AttributeDefinition indexRangeKeyAttributeDefinition = new AttributeDefinition();
private boolean enableIndexRangeKey = false;
private final DataBindingContext bindingContext = new DataBindingContext();
/** The model value objects for data-binding **/
private final IObservableValue indexNameModel;
private final IObservableValue indexHashKeyNameInKeySchemaDefinitionModel;
private final IObservableValue indexHashKeyNameInAttributeDefinitionsModel;
private final IObservableValue indexHashKeyAttributeTypeModel;
private final IObservableValue enableIndexRangeKeyModel;
private final IObservableValue indexRangeKeyNameInKeySchemaDefinitionModel;
private final IObservableValue indexRangeKeyNameInAttributeDefinitionsModel;
private final IObservableValue indexRangeKeyAttributeTypeModel;
private final IObservableValue projectionTypeModel;
private final IObservableValue readCapacityModel;
private final IObservableValue writeCapacityModel;
/** The map from each primary key name to the combo index of its attribute type **/
private final Map<String, Integer> primaryKeyTypes = new HashMap<String, Integer>();
private Font italicFont;
private static final long CAPACITY_UNIT_MINIMUM = 1;
private static final String[] DATA_TYPE_STRINGS = new String[] { "String", "Number", "Binary" };
private static final String[] PROJECTED_ATTRIBUTES = new String[] { "All Attributes", "Table and Index Keys", "Specify Attributes" };
public AddGSIDialog(Shell parentShell, CreateTableDataModel dataModel) {
super(parentShell);
// Initialize the variable necessary for data-binding
globalSecondaryIndex = new GlobalSecondaryIndex();
// The index hash key to be defined by the user
KeySchemaElement indexHashKeySchemaDefinition = new KeySchemaElement()
.withAttributeName(null).withKeyType(KeyType.HASH);
globalSecondaryIndex.withKeySchema(indexHashKeySchemaDefinition);
globalSecondaryIndex.setProjection(new Projection());
globalSecondaryIndex.setProvisionedThroughput(new ProvisionedThroughput());
// Initialize IObservableValue objects that keep track of data variables
indexNameModel = PojoObservables.observeValue(globalSecondaryIndex, "indexName");
indexHashKeyNameInKeySchemaDefinitionModel = PojoObservables.observeValue(indexHashKeySchemaDefinition, "attributeName");
indexHashKeyAttributeTypeModel = PojoObservables.observeValue(indexHashKeyAttributeDefinition, "attributeType");
indexHashKeyNameInAttributeDefinitionsModel = PojoObservables.observeValue(indexHashKeyAttributeDefinition, "attributeName");
enableIndexRangeKeyModel = PojoObservables.observeValue(this, "enableIndexRangeKey");
indexRangeKeyNameInKeySchemaDefinitionModel = PojoObservables.observeValue(indexRangeKeySchemaDefinition, "attributeName");
indexRangeKeyAttributeTypeModel = PojoObservables.observeValue(indexRangeKeyAttributeDefinition, "attributeType");
indexRangeKeyNameInAttributeDefinitionsModel = PojoObservables.observeValue(indexRangeKeyAttributeDefinition, "attributeName");
projectionTypeModel = PojoObservables.observeValue(globalSecondaryIndex.getProjection(), "projectionType");
readCapacityModel = PojoObservables.observeValue(globalSecondaryIndex.getProvisionedThroughput(), "readCapacityUnits");
writeCapacityModel = PojoObservables.observeValue(globalSecondaryIndex.getProvisionedThroughput(), "writeCapacityUnits");
// Get the information of the primary keys
String primaryHashKeyName = dataModel.getHashKeyName();
int primaryHashKeyTypeComboIndex = Arrays.<String>asList(DATA_TYPE_STRINGS).indexOf(dataModel.getHashKeyType());
primaryKeyTypes.put(primaryHashKeyName, primaryHashKeyTypeComboIndex);
if (dataModel.getEnableRangeKey()) {
String primaryRangeKeyName = dataModel.getRangeKeyName();
int primaryRangeKeyTypeComboIndex = Arrays.<String>asList(DATA_TYPE_STRINGS).indexOf(dataModel.getRangeKeyType());
primaryKeyTypes.put(primaryRangeKeyName, primaryRangeKeyTypeComboIndex);
}
setShellStyle(SWT.RESIZE);
}
@Override
protected Control createContents(Composite parent) {
Control contents = super.createContents(parent);
setTitle("Add Global Secondary Index");
setTitleImage(AwsToolkitCore.getDefault().getImageRegistry().get(AwsToolkitCore.IMAGE_AWS_LOGO));
okButton = getButton(IDialogConstants.OK_ID);
okButton.setEnabled(false);
return contents;
}
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.setText("Add Global Secondary Index");
shell.setMinimumSize(400, 700);
}
@Override
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
composite.setLayout(new GridLayout());
composite = new Composite(composite, SWT.NULL);
GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
composite.setLayout(new GridLayout(2, false));
// Index hash key attribute name
Group indexHashKeyGroup = CreateTablePageUtil.newGroup(composite, "Index Hash Key", 2);
new Label(indexHashKeyGroup, SWT.NONE | SWT.READ_ONLY).setText("Index Hash Key Name:");
indexHashKeyNameText = new Text(indexHashKeyGroup, SWT.BORDER);
bindingContext.bindValue(SWTObservables.observeText(indexHashKeyNameText, SWT.Modify), indexHashKeyNameInKeySchemaDefinitionModel);
ChainValidator<String> indexHashKeyNameValidationStatusProvider = new ChainValidator<String>(indexHashKeyNameInKeySchemaDefinitionModel, new NotEmptyValidator("Please provide the index hash key name"));
bindingContext.addValidationStatusProvider(indexHashKeyNameValidationStatusProvider);
bindingContext.bindValue(SWTObservables.observeText(indexHashKeyNameText, SWT.Modify), indexHashKeyNameInAttributeDefinitionsModel);
indexHashKeyNameText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (primaryKeyTypes.containsKey(indexHashKeyNameText.getText())
&& indexHashKeyAttributeTypeCombo != null
&& primaryKeyTypes.get(indexHashKeyNameText.getText()) > -1) {
indexHashKeyAttributeTypeCombo.select(primaryKeyTypes.get(indexHashKeyNameText.getText()));
indexHashKeyAttributeTypeCombo.setEnabled(false);
} else if (indexHashKeyAttributeTypeCombo != null) {
indexHashKeyAttributeTypeCombo.setEnabled(true);
}
}
});
GridDataFactory.fillDefaults().grab(true, false).applyTo(indexHashKeyNameText);
// Index hash key attribute type
new Label(indexHashKeyGroup, SWT.NONE | SWT.READ_ONLY).setText("Index Hash Key Type:");
indexHashKeyAttributeTypeCombo = new Combo(indexHashKeyGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
indexHashKeyAttributeTypeCombo.setItems(DATA_TYPE_STRINGS);
indexHashKeyAttributeTypeCombo.select(0);
bindingContext.bindValue(SWTObservables.observeSelection(indexHashKeyAttributeTypeCombo), indexHashKeyAttributeTypeModel);
Group indexRangeKeyGroup = CreateTablePageUtil.newGroup(composite, "Index Range Key", 2);
// Enable index range key button
enableIndexRangeKeyButton = new Button(indexRangeKeyGroup, SWT.CHECK);
enableIndexRangeKeyButton.setText("Enable Index Range Key");
GridDataFactory.fillDefaults().span(2, 1).applyTo(enableIndexRangeKeyButton);
bindingContext.bindValue(SWTObservables.observeSelection(enableIndexRangeKeyButton), enableIndexRangeKeyModel);
// Index range key attribute name
final Label indexRangeKeyAttributeLabel = new Label(indexRangeKeyGroup, SWT.NONE | SWT.READ_ONLY);
indexRangeKeyAttributeLabel.setText("Index Range Key Name:");
indexRangeKeyNameText = new Text(indexRangeKeyGroup, SWT.BORDER);
bindingContext.bindValue(SWTObservables.observeText(indexRangeKeyNameText, SWT.Modify), indexRangeKeyNameInKeySchemaDefinitionModel);
ChainValidator<String> indexRangeKeyNameValidationStatusProvider = new ChainValidator<String>(
indexRangeKeyNameInKeySchemaDefinitionModel,
enableIndexRangeKeyModel,
new NotEmptyValidator("Please provide the index range key name"));
bindingContext.addValidationStatusProvider(indexRangeKeyNameValidationStatusProvider);
bindingContext.bindValue(SWTObservables.observeText(indexRangeKeyNameText, SWT.Modify), indexRangeKeyNameInAttributeDefinitionsModel);
indexRangeKeyNameText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (primaryKeyTypes.containsKey(indexRangeKeyNameText.getText())
&& indexRangeKeyAttributeTypeCombo != null
&& primaryKeyTypes.get(indexRangeKeyNameText.getText()) > -1) {
indexRangeKeyAttributeTypeCombo.select(primaryKeyTypes.get(indexRangeKeyNameText.getText()));
indexRangeKeyAttributeTypeCombo.setEnabled(false);
} else if (indexRangeKeyAttributeTypeCombo != null) {
indexRangeKeyAttributeTypeCombo.setEnabled(true);
}
}
});
GridDataFactory.fillDefaults().grab(true, false).applyTo(indexRangeKeyNameText);
// Index range key attribute type
final Label indexRangeKeyTypeLabel = new Label(indexRangeKeyGroup, SWT.NONE | SWT.READ_ONLY);
indexRangeKeyTypeLabel.setText("Index Range Key Type:");
indexRangeKeyAttributeTypeCombo = new Combo(indexRangeKeyGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
indexRangeKeyAttributeTypeCombo.setItems(DATA_TYPE_STRINGS);
indexRangeKeyAttributeTypeCombo.select(0);
bindingContext.bindValue(SWTObservables.observeSelection(indexRangeKeyAttributeTypeCombo), indexRangeKeyAttributeTypeModel);
enableIndexRangeKeyButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
enableIndexRangeKey = enableIndexRangeKeyButton.getSelection();
indexRangeKeyAttributeLabel.setEnabled(enableIndexRangeKey);
indexRangeKeyNameText.setEnabled(enableIndexRangeKey);
indexRangeKeyTypeLabel.setEnabled(enableIndexRangeKey);
indexRangeKeyAttributeTypeCombo.setEnabled(enableIndexRangeKey);
}
});
enableIndexRangeKeyButton.setSelection(false);
indexRangeKeyAttributeLabel.setEnabled(false);
indexRangeKeyNameText.setEnabled(false);
indexRangeKeyTypeLabel.setEnabled(false);
indexRangeKeyAttributeTypeCombo.setEnabled(false);
// Index name
Label indexNameLabel = new Label(composite, SWT.NONE | SWT.READ_ONLY);
indexNameLabel.setText("Index Name:");
indexNameText = new Text(composite, SWT.BORDER);
GridDataFactory.fillDefaults().grab(true, false).applyTo(indexNameText);
bindingContext.bindValue(SWTObservables.observeText(indexNameText, SWT.Modify), indexNameModel);
ChainValidator<String> indexNameValidationStatusProvider = new ChainValidator<String>(indexNameModel, new NotEmptyValidator("Please provide an index name"));
bindingContext.addValidationStatusProvider(indexNameValidationStatusProvider);
// Projection type
new Label(composite, SWT.NONE | SWT.READ_ONLY).setText("Projected Attributes:");
projectionTypeCombo = new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY);
projectionTypeCombo.setItems(PROJECTED_ATTRIBUTES);
projectionTypeCombo.select(0);
bindingContext.bindValue(SWTObservables.observeSelection(projectionTypeCombo), projectionTypeModel);
projectionTypeCombo.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
if (projectionTypeCombo.getSelectionIndex() == 2) {
// Enable the list for adding non-key attributes to the projection
addAttributeButton.setEnabled(true);
} else {
addAttributeButton.setEnabled(false);
}
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
// Non-key attributes in the projection
final AttributeList attributeList = new AttributeList(composite);
GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, SWT.DEFAULT).applyTo(attributeList);
addAttributeButton = new Button(composite, SWT.PUSH);
addAttributeButton.setText("Add Attribute");
addAttributeButton.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
addAttributeButton.setImage(AwsToolkitCore.getDefault().getImageRegistry().get(AwsToolkitCore.IMAGE_ADD));
addAttributeButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
AddNewAttributeDialog newAttributeTable = new AddNewAttributeDialog();
if (newAttributeTable.open() == 0) {
// lazy-initialize the list
if (null == globalSecondaryIndex.getProjection().getNonKeyAttributes()) {
globalSecondaryIndex.getProjection().setNonKeyAttributes(new LinkedList<String>());
}
globalSecondaryIndex.getProjection().getNonKeyAttributes().add(newAttributeTable.getNewAttributeName());
attributeList.refresh();
}
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
addAttributeButton.setEnabled(false);
// GSI throughput
FontData[] fontData = indexNameLabel.getFont().getFontData();
for (FontData fd : fontData) {
fd.setStyle(SWT.ITALIC);
}
italicFont = new Font(Display.getDefault(), fontData);
Group throughputGroup = CreateTablePageUtil.newGroup(composite, "Global Secondary Index Throughput", 3);
new Label(throughputGroup, SWT.READ_ONLY).setText("Read Capacity Units:");
final Text readCapacityText = CreateTablePageUtil.newTextField(throughputGroup);
readCapacityText.setText("" + CAPACITY_UNIT_MINIMUM);
bindingContext.bindValue(SWTObservables.observeText(readCapacityText, SWT.Modify), readCapacityModel);
ChainValidator<Long> readCapacityValidationStatusProvider = new ChainValidator<Long>(
readCapacityModel, new RangeValidator(
"Please enter a read capacity of " + CAPACITY_UNIT_MINIMUM + " or more.", CAPACITY_UNIT_MINIMUM,
Long.MAX_VALUE));
bindingContext.addValidationStatusProvider(readCapacityValidationStatusProvider);
Label minimumReadCapacityLabel = new Label(throughputGroup, SWT.READ_ONLY);
minimumReadCapacityLabel.setText("(Minimum capacity " + CAPACITY_UNIT_MINIMUM + ")");
minimumReadCapacityLabel.setFont(italicFont);
new Label(throughputGroup, SWT.READ_ONLY).setText("Write Capacity Units:");
final Text writeCapacityText = CreateTablePageUtil.newTextField(throughputGroup);
writeCapacityText.setText("" + CAPACITY_UNIT_MINIMUM);
Label minimumWriteCapacityLabel = new Label(throughputGroup, SWT.READ_ONLY);
minimumWriteCapacityLabel.setText("(Minimum capacity " + CAPACITY_UNIT_MINIMUM + ")");
minimumWriteCapacityLabel.setFont(italicFont);
bindingContext.bindValue(SWTObservables.observeText(writeCapacityText, SWT.Modify), writeCapacityModel);
ChainValidator<Long> writeCapacityValidationStatusProvider = new ChainValidator<Long>(
writeCapacityModel, new RangeValidator(
"Please enter a write capacity of " + CAPACITY_UNIT_MINIMUM + " or more.", CAPACITY_UNIT_MINIMUM,
Long.MAX_VALUE));
bindingContext.addValidationStatusProvider(writeCapacityValidationStatusProvider);
final Label throughputCapacityLabel = new Label(throughputGroup, SWT.WRAP);
throughputCapacityLabel
.setText("This throughput is separate from and in addition to the primary table's throughput.");
GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
gridData.horizontalSpan = 3;
gridData.widthHint = 200;
throughputCapacityLabel.setLayoutData(gridData);
throughputCapacityLabel.setFont(italicFont);
// Finally provide aggregate status reporting for the entire wizard page
final AggregateValidationStatus aggregateValidationStatus = new AggregateValidationStatus(bindingContext, AggregateValidationStatus.MAX_SEVERITY);
aggregateValidationStatus.addChangeListener(new IChangeListener() {
public void handleChange(ChangeEvent event) {
Object value = aggregateValidationStatus.getValue();
if (value instanceof IStatus == false)
return;
IStatus status = (IStatus) value;
if (status.getSeverity() == Status.ERROR) {
setErrorMessage(status.getMessage());
if (okButton != null) {
okButton.setEnabled(false);
}
} else {
setErrorMessage(null);
if (okButton != null) {
okButton.setEnabled(true);
}
}
}
});
bindingContext.updateModels();
return composite;
}
/** This method should only be called once by the parent wizard. **/
public GlobalSecondaryIndex getGlobalSecondaryIndex() {
if (enableIndexRangeKey) {
globalSecondaryIndex.getKeySchema().add(indexRangeKeySchemaDefinition);
}
return globalSecondaryIndex;
}
/**
* Returns an unmodifiable list of all the AttributeDefinition of the index keys associated with this GSI.
*/
public List<AttributeDefinition> getIndexKeyAttributeDefinitions() {
List<AttributeDefinition> keyAttrs = new LinkedList<AttributeDefinition>();
keyAttrs.add(indexHashKeyAttributeDefinition);
if (isEnableIndexRangeKey() ) {
keyAttrs.add(indexRangeKeyAttributeDefinition);
}
return Collections.unmodifiableList(keyAttrs);
}
public boolean isEnableIndexRangeKey() {
return enableIndexRangeKey;
}
public void setEnableIndexRangeKey(boolean enableIndexRangeKey) {
this.enableIndexRangeKey = enableIndexRangeKey;
}
private class AddNewAttributeDialog extends AbstractAddNewAttributeDialog {
@Override
public void validate() {
if (getButton(0) == null)
return;
if (getNewAttributeName().length() == 0) {
getButton(0).setEnabled(false);
return;
}
getButton(0).setEnabled(true);
return;
}
}
/** The list widget for adding projected non-key attributes. **/
private class AttributeList extends Composite {
private ListViewer viewer;
private AttributeListContentProvider attributeListContentProvider;
public AttributeList(Composite parent) {
super(parent, SWT.NONE);
this.setLayout(new GridLayout());
viewer = new ListViewer(this, SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY);
attributeListContentProvider = new AttributeListContentProvider();
viewer.setContentProvider(attributeListContentProvider);
viewer.setLabelProvider(new LabelProvider());
GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getList());
viewer.getList().setVisible(true);
MenuManager menuManager = new MenuManager("#PopupMenu");
menuManager.setRemoveAllWhenShown(true);
menuManager.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
if (viewer.getList().getSelectionCount() > 0) {
manager.add(new Action() {
@Override
public ImageDescriptor getImageDescriptor() {
return AwsToolkitCore.getDefault().getImageRegistry().getDescriptor(AwsToolkitCore.IMAGE_REMOVE);
}
@Override
public void run() {
// In theory, this should never be null.
if (null != globalSecondaryIndex.getProjection().getNonKeyAttributes()) {
globalSecondaryIndex.getProjection().getNonKeyAttributes().remove(viewer.getList().getSelectionIndex());
}
refresh();
}
@Override
public String getText() {
return "Delete Attribute";
}
});
}
}
});
viewer.getList().setMenu(menuManager.createContextMenu(viewer.getList()));
}
// Enforce to call getElements to update list
public void refresh() {
viewer.setInput(new Object());
}
}
private class AttributeListContentProvider extends ObservableListContentProvider {
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
@Override
public Object[] getElements(Object inputElement) {
return globalSecondaryIndex.getProjection().getNonKeyAttributes() != null ?
globalSecondaryIndex.getProjection().getNonKeyAttributes().toArray()
: new String[] {};
}
}
}