Skip to content

Commit

Permalink
#1811: Hooked up DynamoDB in the desktop UI
Browse files Browse the repository at this point in the history
  • Loading branch information
kaspersorensen committed Mar 7, 2019
1 parent 8b4d57a commit 8cbfc6f
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 4 deletions.
7 changes: 7 additions & 0 deletions desktop/api/src/main/java/org/datacleaner/util/IconUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@
import org.datacleaner.connection.CsvDatastore;
import org.datacleaner.connection.Datastore;
import org.datacleaner.connection.DbaseDatastore;
import org.datacleaner.connection.DynamoDbDatastore;
import org.datacleaner.connection.ElasticSearchDatastore;
import org.datacleaner.connection.ExcelDatastore;
import org.datacleaner.connection.FixedWidthDatastore;
import org.datacleaner.connection.HBaseDatastore;
import org.datacleaner.connection.JdbcDatastore;
import org.datacleaner.connection.JsonDatastore;
import org.datacleaner.connection.KafkaDatastore;
import org.datacleaner.connection.MongoDbDatastore;
import org.datacleaner.connection.Neo4jDatastore;
import org.datacleaner.connection.OdbDatastore;
Expand Down Expand Up @@ -211,6 +213,7 @@ private int brighter(final int rgb, final int percent) {
public static final String COMPOSITE_IMAGEPATH = "images/datastore-types/composite.png";
public static final String MONGODB_IMAGEPATH = "images/datastore-types/mongodb.png";
public static final String COUCHDB_IMAGEPATH = "images/datastore-types/couchdb.png";
public static final String DYNAMODB_IMAGEPATH = "images/datastore-types/dynamodb.png";
public static final String KAFKA_IMAGEPATH = "images/datastore-types/kafka.png";
public static final String SALESFORCE_IMAGEPATH = "images/datastore-types/salesforce.png";
public static final String SUGAR_CRM_IMAGEPATH = "images/datastore-types/sugarcrm.png";
Expand Down Expand Up @@ -551,6 +554,10 @@ protected static String getDatastoreImagePath(final Datastore datastore,
imagePath = JSON_IMAGEPATH;
} else if (datastore instanceof CouchDbDatastore) {
imagePath = COUCHDB_IMAGEPATH;
} else if (datastore instanceof DynamoDbDatastore) {
imagePath = DYNAMODB_IMAGEPATH;
} else if (datastore instanceof KafkaDatastore) {
imagePath = KAFKA_IMAGEPATH;
} else if (datastore instanceof MongoDbDatastore) {
imagePath = MONGODB_IMAGEPATH;
} else if (datastore instanceof SalesforceDatastore) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.datacleaner.windows.CouchDbDatastoreDialog;
import org.datacleaner.windows.CsvDatastoreDialog;
import org.datacleaner.windows.DbaseDatastoreDialog;
import org.datacleaner.windows.DynamoDbDatastoreDialog;
import org.datacleaner.windows.ElasticSearchDatastoreDialog;
import org.datacleaner.windows.ExcelDatastoreDialog;
import org.datacleaner.windows.FixedWidthDatastoreDialog;
Expand Down Expand Up @@ -99,6 +100,10 @@ public class DatastoreDescriptors {
new DatastoreDescriptorImpl("CouchDB database", "Connect to an Apache CouchDB database",
CouchDbDatastore.class, CouchDbDatastoreDialog.class, IconUtils.COUCHDB_IMAGEPATH, true);

private static final DatastoreDescriptor DYNAMODB_DATASTORE_DESCRIPTOR =
new DatastoreDescriptorImpl("AWS DynamoDB database", "Connect to an AWS DynamoDB database",
DynamoDbDatastore.class, DynamoDbDatastoreDialog.class, IconUtils.DYNAMODB_IMAGEPATH, true);

private static final DatastoreDescriptor KAFKA_DATASTORE_DESCRIPTOR =
new DatastoreDescriptorImpl("Kafka stream", "Connect to an Apache Kafka stream",
KafkaDatastore.class, KafkaDatastoreDialog.class, IconUtils.KAFKA_IMAGEPATH, true);
Expand Down Expand Up @@ -206,6 +211,7 @@ public List<DatastoreDescriptor> getAvailableDatabaseBasedDatastoreDescriptors()
availableCloudBasedDatabaseDescriptors.add(CASSANDRA_DATASTORE_DESCRIPTOR);
availableCloudBasedDatabaseDescriptors.add(MONGODB_DATASTORE_DESCRIPTOR);
availableCloudBasedDatabaseDescriptors.add(COUCHDB_DATASTORE_DESCRIPTOR);
availableCloudBasedDatabaseDescriptors.add(DYNAMODB_DATASTORE_DESCRIPTOR);
availableCloudBasedDatabaseDescriptors.add(KAFKA_DATASTORE_DESCRIPTOR);
availableCloudBasedDatabaseDescriptors.add(NEO4J_DATASTORE_DESCRIPTOR);

Expand All @@ -227,6 +233,7 @@ private List<DatastoreDescriptor> getManualDatastoreDescriptors() {
datastoreDescriptors.add(SUGARCRM_DATASTORE_DESCRIPTOR);
datastoreDescriptors.add(MONGODB_DATASTORE_DESCRIPTOR);
datastoreDescriptors.add(COUCHDB_DATASTORE_DESCRIPTOR);
datastoreDescriptors.add(DYNAMODB_DATASTORE_DESCRIPTOR);
datastoreDescriptors.add(KAFKA_DATASTORE_DESCRIPTOR);
datastoreDescriptors.add(ELASTICSEARCH_DATASTORE_DESCRIPTOR);
datastoreDescriptors.add(CASSANDRA_DATASTORE_DESCRIPTOR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.datacleaner.connection.Datastore;
import org.datacleaner.connection.DatastoreConnection;
import org.datacleaner.connection.DbaseDatastore;
import org.datacleaner.connection.DynamoDbDatastore;
import org.datacleaner.connection.ElasticSearchDatastore;
import org.datacleaner.connection.ExcelDatastore;
import org.datacleaner.connection.FileDatastore;
Expand Down Expand Up @@ -70,6 +71,7 @@
import org.datacleaner.windows.CouchDbDatastoreDialog;
import org.datacleaner.windows.CsvDatastoreDialog;
import org.datacleaner.windows.DbaseDatastoreDialog;
import org.datacleaner.windows.DynamoDbDatastoreDialog;
import org.datacleaner.windows.ElasticSearchDatastoreDialog;
import org.datacleaner.windows.ExcelDatastoreDialog;
import org.datacleaner.windows.FixedWidthDatastoreDialog;
Expand Down Expand Up @@ -116,7 +118,7 @@ public DatastorePanel(final Datastore datastore, final MutableDatastoreCatalog d

setOpaque(false);

final Icon icon = IconUtils.getDatastoreIcon(datastore);
final Icon icon = IconUtils.getDatastoreIcon(datastore, IconUtils.ICON_SIZE_LARGE);
final String description = getDescription(datastore);

_checkBox = new JCheckBox();
Expand Down Expand Up @@ -179,7 +181,7 @@ public static String getDescription(final Datastore datastore) {
return datasourceJndiUrl;
} else if (datastore instanceof ElasticSearchDatastore) {
final ElasticSearchDatastore elasticSearchDatastore = (ElasticSearchDatastore) datastore;
return elasticSearchDatastore.getClusterName() + " - " + elasticSearchDatastore.getIndexName();
return elasticSearchDatastore.getIndexName();
} else if (datastore instanceof CassandraDatastore) {
final CassandraDatastore cassandraDatastore = (CassandraDatastore) datastore;
return cassandraDatastore.getKeyspace();
Expand Down Expand Up @@ -335,6 +337,12 @@ private JButton createEditButton(final Datastore datastore) {
final CouchDbDatastoreDialog dialog = injector.getInstance(CouchDbDatastoreDialog.class);
dialog.open();
});
} else if (datastore instanceof DynamoDbDatastore) {
editButton.addActionListener(e -> {
final Injector injector = getInjectorBuilder().with(DynamoDbDatastore.class, datastore).createInjector();
final DynamoDbDatastoreDialog dialog = injector.getInstance(DynamoDbDatastoreDialog.class);
dialog.open();
});
} else if (datastore instanceof MongoDbDatastore) {
editButton.addActionListener(e -> {
final Injector injector = getInjectorBuilder().with(MongoDbDatastore.class, datastore).createInjector();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/**
* DataCleaner (community edition)
* Copyright (C) 2014 Free Software Foundation, Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.datacleaner.windows;

import java.util.List;
import java.util.Map.Entry;

import javax.inject.Inject;
import javax.swing.JComponent;
import javax.swing.JPasswordField;
import javax.swing.event.DocumentEvent;

import org.apache.metamodel.schema.Schema;
import org.apache.metamodel.util.SimpleTableDef;
import org.datacleaner.bootstrap.WindowContext;
import org.datacleaner.connection.DynamoDbDatastore;
import org.datacleaner.connection.UpdateableDatastoreConnection;
import org.datacleaner.guice.Nullable;
import org.datacleaner.user.MutableDatastoreCatalog;
import org.datacleaner.user.UserPreferences;
import org.datacleaner.util.DCDocumentListener;
import org.datacleaner.util.IconUtils;
import org.datacleaner.util.ImmutableEntry;
import org.datacleaner.util.SchemaFactory;
import org.datacleaner.util.StringUtils;
import org.datacleaner.util.WidgetFactory;
import org.datacleaner.widgets.DCComboBox;
import org.datacleaner.widgets.TableDefinitionOptionSelectionPanel;
import org.jdesktop.swingx.JXTextField;

import com.amazonaws.regions.Regions;

public class DynamoDbDatastoreDialog extends AbstractDatastoreDialog<DynamoDbDatastore> implements SchemaFactory {

private static final long serialVersionUID = 1L;

private final DCComboBox<Regions> _regionField;
private final JXTextField _accessKeyField;
private final JPasswordField _accessSecretField;
private final TableDefinitionOptionSelectionPanel _tableDefinitionWidget;

@Inject
public DynamoDbDatastoreDialog(final WindowContext windowContext, final MutableDatastoreCatalog catalog,
@Nullable final DynamoDbDatastore originalDatastore, final UserPreferences userPreferences) {
super(originalDatastore, catalog, windowContext, userPreferences);

_regionField = new DCComboBox<>(Regions.values());
_regionField.setSelectedItem(Regions.DEFAULT_REGION);
_accessKeyField = WidgetFactory.createTextField();
_accessSecretField = WidgetFactory.createPasswordField();

_accessKeyField.getDocument().addDocumentListener(new DCDocumentListener() {
@Override
protected void onChange(final DocumentEvent event) {
validateAndUpdate();
}
});
_accessSecretField.getDocument().addDocumentListener(new DCDocumentListener() {
@Override
protected void onChange(final DocumentEvent event) {
validateAndUpdate();
}
});

if (originalDatastore == null) {
_tableDefinitionWidget = new TableDefinitionOptionSelectionPanel(windowContext, this, null);
} else {
_datastoreNameTextField.setText(originalDatastore.getName());
_datastoreNameTextField.setEnabled(false);
_accessKeyField.setText(originalDatastore.getAccessKey());
_accessSecretField.setText(originalDatastore.getAccessSecret());
final String originalRegion = originalDatastore.getRegion();
try {
final Regions region = Regions.fromName(originalRegion);
_regionField.setSelectedItem(region);
} catch (IllegalArgumentException e) {
// unable to resolve region, ignore.
}
_tableDefinitionWidget =
new TableDefinitionOptionSelectionPanel(windowContext, this, originalDatastore.getTableDefs());
}
}

@Override
public String getWindowTitle() {
return "AWS DynamoDB database";
}

@Override
protected String getBannerTitle() {
return "AWS DynamoDB database";
}

@Override
protected boolean validateForm() {
final String datastoreName = _datastoreNameTextField.getText();
if (StringUtils.isNullOrEmpty(datastoreName)) {
setStatusError("Please enter a datastore name");
return false;
}

setStatusValid();
return true;
}

protected DynamoDbDatastore createDatastore() {
final String name = _datastoreNameTextField.getText();
final String region = _regionField.getSelectedItem().getName();
final String accessKey = _accessKeyField.getText();
final String accessSecret = new String(_accessSecretField.getPassword());
final SimpleTableDef[] tableDefs = _tableDefinitionWidget.getTableDefs();
return new DynamoDbDatastore(name, region, accessKey, accessSecret, tableDefs);
}

@Override
public Schema createSchema() {
final DynamoDbDatastore datastore = createDatastore();
try (UpdateableDatastoreConnection con = datastore.openConnection()) {
return con.getDataContext().getDefaultSchema();
}
}

@Override
protected String getDatastoreIconPath() {
return IconUtils.DYNAMODB_IMAGEPATH;
}

@Override
protected List<Entry<String, JComponent>> getFormElements() {
final List<Entry<String, JComponent>> result = super.getFormElements();
result.add(new ImmutableEntry<>("Region", _regionField));
result.add(new ImmutableEntry<>("Access Key", _accessKeyField));
result.add(new ImmutableEntry<>("Access Secret", _accessSecretField));
result.add(new ImmutableEntry<>("Schema model", _tableDefinitionWidget));
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
/**
* Datastore providing access to AWS DynamoDB
*/
public class DynamoDbDatastore extends UsageAwareDatastore<DynamoDbDataContext> {
public class DynamoDbDatastore extends UsageAwareDatastore<DynamoDbDataContext> implements UpdateableDatastore {

private static final long serialVersionUID = 1L;

Expand All @@ -56,6 +56,11 @@ public PerformanceCharacteristics getPerformanceCharacteristics() {
return new PerformanceCharacteristicsImpl(false, true);
}

@Override
public UpdateableDatastoreConnection openConnection() {
return (UpdateableDatastoreConnection) super.openConnection();
}

@Override
protected UsageAwareDatastoreConnection<DynamoDbDataContext> createDatastoreConnection() {
final AmazonDynamoDBClientBuilder clientBuilder = AmazonDynamoDBClientBuilder.standard();
Expand All @@ -71,7 +76,7 @@ protected UsageAwareDatastoreConnection<DynamoDbDataContext> createDatastoreConn
clientBuilder.setCredentials(credentialsProvider);
final AmazonDynamoDB client = clientBuilder.build();
final DynamoDbDataContext dataContext = new DynamoDbDataContext(client, _tableDefs);
return new DatastoreConnectionImpl<>(dataContext, this);
return new UpdateableDatastoreConnectionImpl<>(dataContext, this);
}

public String getAccessKey() {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 8cbfc6f

Please sign in to comment.