diff --git a/.travis.yml b/.travis.yml index 125ad8f..94e3c54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,5 +22,4 @@ deploy: draft: true on: branch: master - tags: true - condition: "$TRAVIS_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+" \ No newline at end of file + tags: true \ No newline at end of file diff --git a/pom.xml b/pom.xml index 34ea7f3..2922f5f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.erikmafo bigtableviewer - 0.1.2 + 0.1.3-SNAPSHOT jar bigtableviewer @@ -187,7 +187,7 @@ com.google.cloud.bigtable - bigtable-hbase-1.x + bigtable-hbase-1.x-shaded 1.7.0 @@ -196,6 +196,11 @@ 1 compile + + javax.annotation + javax.annotation-api + 1.3.2 + com.google.code.gson gson @@ -231,5 +236,10 @@ 1.10.19 test + + com.google.inject + guice + 4.2.2 + \ No newline at end of file diff --git a/src/main/java/com/erikmafo/btviewer/MainApp.java b/src/main/java/com/erikmafo/btviewer/MainApp.java index 7271334..4a34f0a 100644 --- a/src/main/java/com/erikmafo/btviewer/MainApp.java +++ b/src/main/java/com/erikmafo/btviewer/MainApp.java @@ -1,4 +1,10 @@ package com.erikmafo.btviewer; +import com.erikmafo.btviewer.services.BigtableClient; +import com.erikmafo.btviewer.services.BigtableInstanceManager; +import com.erikmafo.btviewer.services.CredentialsManager; +import com.google.inject.Binder; +import com.google.inject.Guice; +import com.google.inject.Module; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; @@ -9,7 +15,8 @@ /** * Created by erikmafo on 12.12.17. */ -public class MainApp extends Application { +public class MainApp extends Application implements Module { + public static void main(String[] args) { launch(args); } @@ -17,6 +24,7 @@ public static void main(String[] args) { @Override public void start(Stage primaryStage) throws Exception{ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/main.fxml")); + loader.setControllerFactory(Guice.createInjector(this)::getInstance); Parent root = loader.load(); primaryStage.setTitle("Bigtable viewer"); primaryStage.setScene(new Scene(root, 800, 700)); @@ -27,4 +35,11 @@ public void start(Stage primaryStage) throws Exception{ public void stop() throws Exception { super.stop(); } + + @Override + public void configure(Binder binder) { + binder.bind(BigtableClient.class).toInstance(new BigtableClient()); + binder.bind(CredentialsManager.class).toInstance(new CredentialsManager()); + binder.bind(BigtableInstanceManager.class).toInstance(new BigtableInstanceManager()); + } } diff --git a/src/main/java/com/erikmafo/btviewer/components/BigtableView.java b/src/main/java/com/erikmafo/btviewer/components/BigtableTableView.java similarity index 72% rename from src/main/java/com/erikmafo/btviewer/components/BigtableView.java rename to src/main/java/com/erikmafo/btviewer/components/BigtableTableView.java index 4368564..ebf1328 100644 --- a/src/main/java/com/erikmafo/btviewer/components/BigtableView.java +++ b/src/main/java/com/erikmafo/btviewer/components/BigtableTableView.java @@ -2,18 +2,19 @@ import com.erikmafo.btviewer.model.BigtableColumn; import com.erikmafo.btviewer.model.BigtableRow; -import com.erikmafo.btviewer.services.BigtableResultScanner; -import javafx.application.Platform; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.geometry.Orientation; import javafx.scene.Node; import javafx.scene.control.*; -import javafx.scene.layout.GridPane; +import javafx.scene.input.ScrollEvent; +import javafx.scene.layout.VBox; import java.io.IOException; import java.util.*; @@ -22,18 +23,19 @@ /** * Created by erikmafo on 12.12.17. */ -public class BigtableView extends GridPane { +public class BigtableTableView extends VBox { - public static final String ROWKEY = "rowkey"; + private static final String ROWKEY = "rowkey"; @FXML - private TableView tableView; + private Button configureRowValueTypesButton; - private BigtableResultScanner scanner; + @FXML + private TableView tableView; - public BigtableView() { + public BigtableTableView() { - FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/bigtable_view.fxml")); + FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/bigtable_table_view.fxml")); loader.setRoot(this); loader.setController(this); @@ -44,10 +46,7 @@ public BigtableView() { } tableView.getColumns().add(createRowKeyColumn()); - tableView.setOnScroll(event -> { - ScrollBar bar = getVerticalScrollbar(); - Platform.runLater(() -> addRows((int)bar.getMax())); - }); + configureRowValueTypesButton.setVisible(false); // TODO: enable this feature } private ScrollBar getVerticalScrollbar() { @@ -72,6 +71,19 @@ private ScrollBar getVerticalScrollbar() { return tableColumn; } + public int getMaxRows() { + ScrollBar bar = getVerticalScrollbar(); + return (int)bar.getMax(); + } + + public void setOnConfigureRowValuesTypes(EventHandler eventHandler) { + configureRowValueTypesButton.setOnAction(eventHandler); + } + + public void setOnScrollEvent(EventHandler eventHandler) { + getVerticalScrollbar().setOnScroll(eventHandler); + } + public List getColumns() { return tableView.getColumns() .stream() @@ -82,24 +94,13 @@ public List getColumns() { .collect(Collectors.toList()); } - public void setBigtableScanner(BigtableResultScanner scanner) - { - if (this.scanner != null) - { - BigtableResultScanner prevScanner = this.scanner; - Platform.runLater(() -> - { - try { - prevScanner.close(); - } catch (IOException e) { - e.printStackTrace(); - } - }); - } - this.scanner = scanner; + public void clear() { tableView.getColumns().removeIf(t -> !t.getText().equals(ROWKEY)); setBigTableRows(FXCollections.observableArrayList()); - Platform.runLater(() -> addRows(20)); + } + + public void add(BigtableRow row) { + tableView.getItems().add(row); } private void addColumn(String family, String qualifier) { @@ -116,7 +117,6 @@ private void addColumn(String family, String qualifier) { return new ReadOnlyObjectWrapper<>(bigtableRow.getCellValue(family, qualifier)); }); - if (familyColumn == null) { familyColumn = new TableColumn<>(family); familyColumn.getColumns().add(qualifierColumn); @@ -137,22 +137,4 @@ private void setBigTableRows(ObservableList bigtableRows) { } }); } - - private void addRows(int maxRows) { - int count = 0; - - BigtableRow row; - do { - try { - row = scanner.next(); - if (row == null) { - break; - } - tableView.getItems().add(row); - count++; - } catch (IOException e) { - e.printStackTrace(); - } - } while (count < maxRows); - } } diff --git a/src/main/java/com/erikmafo/btviewer/components/BigtableTablesListView.java b/src/main/java/com/erikmafo/btviewer/components/BigtableTablesListView.java index 6ee59ec..e00ed17 100644 --- a/src/main/java/com/erikmafo/btviewer/components/BigtableTablesListView.java +++ b/src/main/java/com/erikmafo/btviewer/components/BigtableTablesListView.java @@ -1,22 +1,23 @@ package com.erikmafo.btviewer.components; +import com.erikmafo.btviewer.events.BigtableProjectTreeItemExpanded; import com.erikmafo.btviewer.model.BigtableInstance; import com.erikmafo.btviewer.model.BigtableTable; import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.control.*; -import javafx.scene.layout.GridPane; +import javafx.scene.layout.VBox; import java.io.IOException; import java.util.List; +import java.util.stream.Collectors; -public class BigtableTablesListView extends GridPane { +public class BigtableTablesListView extends VBox { @FXML private Button addInstanceButton; @@ -26,9 +27,7 @@ public class BigtableTablesListView extends GridPane { private SimpleObjectProperty selectedTableProperty; - private SimpleObjectProperty selectedInstanceProperty = new SimpleObjectProperty<>(); - - private SimpleStringProperty selectedProjectProperty = new SimpleStringProperty(); + private EventHandler treeItemExpandedEventHandler; public BigtableTablesListView(){ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/bigtable_tables_list_view.fxml")); @@ -62,11 +61,15 @@ private static int countParents(TreeItem treeItem) { return 1 + countParents(treeItem.getParent()); } - public void setOnAddBigtableInstance(EventHandler eventHandler) { + public void setOnCreateNewBigtableInstance(EventHandler eventHandler) { addInstanceButton.setOnAction(eventHandler); } - public void addBigtableInstance(BigtableInstance instance, ChangeListener expandedListener) { + public void addBigtableInstances(List bigtableInstances) { + bigtableInstances.forEach(this::addBigtableInstance); + } + + public void addBigtableInstance(BigtableInstance instance) { TreeItem projectTreeItem = treeView.getRoot() .getChildren() @@ -75,7 +78,21 @@ public void addBigtableInstance(BigtableInstance instance, ChangeListener(instance.getProjectId()); + final TreeItem projectTreeItemFinal = new TreeItem<>(instance.getProjectId()); + + projectTreeItemFinal.expandedProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observableValue, Boolean wasExpanded, Boolean isExpanded) { + if (isExpanded && treeItemExpandedEventHandler != null) { + List bigtableInstances = projectTreeItemFinal.getChildren() + .stream() + .map(i -> new BigtableInstance(instance.getProjectId(), i.getValue())) + .collect(Collectors.toList()); + treeItemExpandedEventHandler.handle(new BigtableProjectTreeItemExpanded(bigtableInstances)); + } + } + }); + projectTreeItem = projectTreeItemFinal; } TreeItem instanceTreeItem = new TreeItem<>(instance.getInstanceId()); @@ -103,21 +120,10 @@ public void addBigtableTables(List tables) { instance.getChildren().add(new TreeItem<>(table.getTableId())); } }); - } } - private MenuItem getMenuItem(BigtableInstance instance) { - MenuItem menuItem = new MenuItem(instance.getInstanceId()); - menuItem.setUserData(instance); - return menuItem; - } - - public ReadOnlyObjectProperty selectedInstanceProperty() { - return selectedInstanceProperty; - } - - public ReadOnlyStringProperty selectedProjectProperty() { - return selectedProjectProperty; + public void setTreeItemExpandedEventHandler(EventHandler treeItemExpandedEventHandler) { + this.treeItemExpandedEventHandler = treeItemExpandedEventHandler; } } diff --git a/src/main/java/com/erikmafo/btviewer/components/BigtableValueTypesDialog.java b/src/main/java/com/erikmafo/btviewer/components/BigtableValueTypesDialog.java index 7076f49..efd32d3 100644 --- a/src/main/java/com/erikmafo/btviewer/components/BigtableValueTypesDialog.java +++ b/src/main/java/com/erikmafo/btviewer/components/BigtableValueTypesDialog.java @@ -4,7 +4,6 @@ import com.erikmafo.btviewer.model.CellDefinition; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; -import javafx.collections.transformation.SortedList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; @@ -32,7 +31,6 @@ public class BigtableValueTypesDialog extends DialogPane { private BigtableValueTypesDialog() { FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/bigtable_value_types_dialog.fxml")); - loader.setRoot(this); loader.setController(this); diff --git a/src/main/java/com/erikmafo/btviewer/components/RowSelectionView.java b/src/main/java/com/erikmafo/btviewer/components/RowSelectionView.java new file mode 100644 index 0000000..fce5014 --- /dev/null +++ b/src/main/java/com/erikmafo/btviewer/components/RowSelectionView.java @@ -0,0 +1,49 @@ +package com.erikmafo.btviewer.components; + +import com.erikmafo.btviewer.events.ScanTableAction; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.Button; +import javafx.scene.control.ProgressBar; +import javafx.scene.control.TextField; +import javafx.scene.layout.VBox; + +import java.io.IOException; + +public class RowSelectionView extends VBox { + + @FXML + private Button scanTableButton; + + @FXML + private ProgressBar progressBar; + + @FXML + private TextField fromTextField; + + @FXML + private TextField toTextField; + + public RowSelectionView() { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/row_selection_view.fxml")); + loader.setRoot(this); + loader.setController(this); + + try { + loader.load(); + } catch (IOException e) { + throw new RuntimeException("Unable to load fxml", e); + } + progressBar.setVisible(false); + } + + public void setOnScanTable(EventHandler eventHandler) { + scanTableButton.setOnAction(actionEvent -> + eventHandler.handle(new ScanTableAction(fromTextField.getText(), toTextField.getText()))); + } + + public ProgressBar getProgressBar() { + return progressBar; + } +} diff --git a/src/main/java/com/erikmafo/btviewer/components/SpecifyCredentialsPathDialog.java b/src/main/java/com/erikmafo/btviewer/components/SpecifyCredentialsPathDialog.java new file mode 100644 index 0000000..9232476 --- /dev/null +++ b/src/main/java/com/erikmafo/btviewer/components/SpecifyCredentialsPathDialog.java @@ -0,0 +1,106 @@ +package com.erikmafo.btviewer.components; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.*; +import javafx.stage.FileChooser; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; + +public class SpecifyCredentialsPathDialog extends DialogPane { + + @FXML + private TextField credentialsPathTextField; + + public SpecifyCredentialsPathDialog() { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/specify_credentials_path_dialog.fxml")); + + loader.setController(this); + loader.setRoot(this); + try { + loader.load(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + @FXML + private void handleEditCredentialsPathAction(ActionEvent event) { + + FileChooser fileChooser = new FileChooser(); + FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("json files (*.json)", "*.json"); + fileChooser.getExtensionFilters().add(extFilter); + File file = fileChooser.showOpenDialog(getScene().getWindow()); + + if (file != null) + { + credentialsPathTextField.setText(file.getPath()); + } + + } + + public static CompletableFuture displayAndAwaitResult(Path currentPath) { + + CompletableFuture result = new CompletableFuture<>(); + + Dialog dialog = new Dialog<>(); + SpecifyCredentialsPathDialog credentialsPathDialog = new SpecifyCredentialsPathDialog(); + + if (currentPath != null) { + credentialsPathDialog.credentialsPathTextField.textProperty().setValue(currentPath.toString()); + } + + dialog.setDialogPane(credentialsPathDialog); + + dialog.setResultConverter(param -> { + if (ButtonBar.ButtonData.OK_DONE.equals(param.getButtonData())) { + return credentialsPathDialog.credentialsPathTextField.textProperty().get(); + } + return null; + }); + + dialog.setOnHidden(event1 -> { + String pathAsString = dialog.getResult(); + if (pathAsString != null) { + try { + Path path = Path.of(pathAsString); + if (Files.exists(path)) { + if (Files.isReadable(path)) { + result.complete(path); + } else { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle("Invalid path"); + alert.setHeaderText("Please specify a valid path"); + alert.setContentText("File is not readable"); + alert.showAndWait(); + } + } else { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle("Invalid path"); + alert.setHeaderText("Please specify a valid path"); + alert.setContentText("File not found"); + alert.showAndWait(); + } + } catch (InvalidPathException e) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle("Invalid path"); + alert.setHeaderText("Please specify a valid path"); + alert.setContentText(e.getMessage()); + alert.showAndWait(); + } + } + }); + + dialog.show(); + + return result; + } + +} diff --git a/src/main/java/com/erikmafo/btviewer/controllers/BigtableMenuBarController.java b/src/main/java/com/erikmafo/btviewer/controllers/BigtableMenuBarController.java deleted file mode 100644 index 02943d4..0000000 --- a/src/main/java/com/erikmafo/btviewer/controllers/BigtableMenuBarController.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.erikmafo.btviewer.controllers; - -import com.erikmafo.btviewer.model.BigtableValueParser; -import com.erikmafo.btviewer.model.CredentialsRecord; -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; - -import javax.inject.Inject; -import java.util.List; - -public class BigtableMenuBarController { - - @Inject - public BigtableMenuBarController() { - } - - @FXML - private Menu selectTableMenu; - - @FXML - private MenuItem credentialsMenu; - - public void handleManageCredentialsAction(ActionEvent event) { - - } - - public void handleCreateNewTableAction(ActionEvent event) { - - } - - public void addBigtableDefinitions(List bigtableDefinitions) { - //bigtableDefinitions.forEach(this::addBigtableDefinition); - } - - public void addCredentialRecords(List records) { - - } -} diff --git a/src/main/java/com/erikmafo/btviewer/controllers/MainController.java b/src/main/java/com/erikmafo/btviewer/controllers/MainController.java index c6c22a0..2f1aefb 100644 --- a/src/main/java/com/erikmafo/btviewer/controllers/MainController.java +++ b/src/main/java/com/erikmafo/btviewer/controllers/MainController.java @@ -1,33 +1,18 @@ package com.erikmafo.btviewer.controllers; -import com.erikmafo.btviewer.components.BigtableInstanceDialog; -import com.erikmafo.btviewer.components.BigtableValueTypesDialog; -import com.erikmafo.btviewer.components.BigtableTablesListView; -import com.erikmafo.btviewer.components.BigtableView; +import com.erikmafo.btviewer.components.*; +import com.erikmafo.btviewer.events.BigtableProjectTreeItemExpanded; +import com.erikmafo.btviewer.events.ScanTableAction; import com.erikmafo.btviewer.model.*; -import com.erikmafo.btviewer.services.BigtableClient; -import com.erikmafo.btviewer.services.BigtableResultScanner; -import com.erikmafo.btviewer.services.UserConfigurationService; -import javafx.application.Platform; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.concurrent.Service; -import javafx.concurrent.Task; +import com.erikmafo.btviewer.services.*; +import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.control.Label; -import javafx.scene.control.MenuBar; -import javafx.scene.control.ProgressBar; -import javafx.scene.control.TextField; -import javafx.scene.layout.VBox; import javax.inject.Inject; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; import java.util.List; -import java.util.stream.Collectors; /** * Created by erikmafo on 23.12.17. @@ -35,183 +20,115 @@ public class MainController { @FXML - private BigtableTablesListView tablesListView; - - @FXML - private MenuBar bigtableMenuBar; - - @FXML - private BigtableMenuBarController bigtableMenuBarController; + private RowSelectionView rowSelectionView; @FXML - private ProgressBar progressBar; - - @FXML - private VBox mainView; - - @FXML - private TextField fromTextField; - - @FXML - private TextField toTextField; + private BigtableTablesListView tablesListView; @FXML private Label tableNameLabel; @FXML - private BigtableView bigtableView; + private BigtableTableView bigtableTableView; - private final FetchBigtableRowsService fetchBigtableRowsService; - private final UserConfigurationService userConfigurationService; - private final ObservableList bigtableRows = FXCollections.observableArrayList(new ArrayList<>()); + private final CredentialsManager credentialsManager; + private final BigtableInstanceManager bigtableInstanceManager; private final BigtableClient bigtableClient; @Inject - public MainController() { - this.userConfigurationService = new UserConfigurationService(); - this.bigtableClient = new BigtableClient(); - this.fetchBigtableRowsService = new FetchBigtableRowsService(bigtableClient); + public MainController(CredentialsManager credentialsManager, + BigtableInstanceManager bigtableInstanceManager, + BigtableClient bigtableClient) { + this.credentialsManager = credentialsManager; + this.bigtableInstanceManager = bigtableInstanceManager; + this.bigtableClient = bigtableClient; } public void initialize() { - - final String os = System.getProperty("os.name"); - if (os != null && os.startsWith("Mac")) { - bigtableMenuBar.useSystemMenuBarProperty().set(true); - } - - mainView.setVisible(false); - progressBar.progressProperty().bind(fetchBigtableRowsService.progressProperty()); - progressBar.visibleProperty().bind(fetchBigtableRowsService.runningProperty()); - - fetchBigtableRowsService.setOnSucceeded(event -> { - mainView.setVisible(true); - List rows = fetchBigtableRowsService.getValue(); - bigtableRows.setAll(rows); - }); - - tablesListView.selectedTableProperty().addListener((observable, oldValue, newValue) -> - { - bigtableRows.clear(); - mainView.setVisible(true); - tableNameLabel.setText(newValue.getSimpleName()); - BigtableReadRequest request = new BigtableReadRequestBuilder() - .setCredentialsPath(userConfigurationService.getCredentialsPath()) - .setBigtableTable(newValue) - .setScan(new BigtableRowRange("", "~", 100)) - .build(); - try { - bigtableView.setBigtableScanner(bigtableClient.execute(request)); - } catch (IOException e) { - e.printStackTrace(); + rowSelectionView.setVisible(false); + bigtableTableView.setVisible(false); + tableNameLabel.setVisible(false); + + bigtableTableView.setOnConfigureRowValuesTypes(this::onConfigureRowValueTypes); + tablesListView.setOnCreateNewBigtableInstance(this::onAddNewBigtableInstance); + tablesListView.selectedTableProperty().addListener(this::onBigtableTableSelected); + tablesListView.setTreeItemExpandedEventHandler(new EventHandler() { + @Override + public void handle(BigtableProjectTreeItemExpanded event) { + event.getBigtableInstances().forEach(MainController.this::listBigtableTables); } }); + rowSelectionView.setOnScanTable(this::onScanTableAction); - tablesListView.setOnAddBigtableInstance(event -> { - BigtableInstanceDialog.displayAndAwaitResult() - .whenComplete((instance, throwable) -> { - tablesListView.addBigtableInstance(instance, null); - Platform.runLater(() -> tablesListView.addBigtableTables(tryListBigtableTables(instance))); - }); - }); + + tablesListView.addBigtableInstances(bigtableInstanceManager.getInstances()); } - private List tryListBigtableTables(BigtableInstance instance) { - try { - return bigtableClient.listTables( - instance, - userConfigurationService.getCredentialsPath()) - .stream() - .map(this::getBigtableTable) - .collect(Collectors.toList()); - } catch (IOException e) { - return Collections.emptyList(); - } + private void onAddNewBigtableInstance(ActionEvent event) { + BigtableInstanceDialog.displayAndAwaitResult() + .whenComplete((instance, throwable) -> { + List allInstances = bigtableInstanceManager.getInstances(); + allInstances.add(instance); + bigtableInstanceManager.setInstances(allInstances); + + tablesListView.addBigtableInstance(instance); + listBigtableTables(instance); + }); } - private List tryListBigtableInstances(String projectId) { - try { - return bigtableClient.listInstances(projectId, userConfigurationService.getCredentialsPath()); - } catch (IOException e) { - return Collections.emptyList(); - } + private void listBigtableTables(BigtableInstance instance) { + ListBigtableTables listBigtableTables = new ListBigtableTables( + bigtableClient, instance, credentialsManager.getCredentialsPath()); + listBigtableTables.setOnSucceeded(workerStateEvent -> { + tablesListView.addBigtableTables(listBigtableTables.getValue()); + }); + listBigtableTables.start(); } - public void handleScanTableAction(ActionEvent actionEvent) { + private void onScanTableAction(ScanTableAction actionEvent) { + BigtableTable currentTable = tablesListView.selectedTableProperty().get(); + bigtableTableView.clear(); BigtableReadRequest request = new BigtableReadRequestBuilder() - .setCredentialsPath(userConfigurationService.getCredentialsPath()) - .setBigtableTable(tablesListView.selectedTableProperty().get()) - .setScan(new BigtableRowRange(fromTextField.getText(), toTextField.getText())) + .setCredentialsPath(credentialsManager.getCredentialsPath()) + .setTable(currentTable) + .setRowRange(new BigtableRowRange(actionEvent.getFrom(), actionEvent.getTo())) .build(); - try { - bigtableView.setBigtableScanner(bigtableClient.execute(request)); - } catch (IOException e) { - e.printStackTrace(); - } - - //fetchBigtableRowsService.setReadRequest(request); - //fetchBigtableRowsService.restart(); - } - - private BigtableTable getBigtableTable(String tableName) { - return userConfigurationService - .loadBigtableDefinitions() - .stream() - .filter(def -> tableName.equals(def.getName())) - .findFirst().orElse(new BigtableTable(tableName)); + readBigtableRows(request); } - public void handleConfigureValueParserAction(ActionEvent event) { - BigtableValueTypesDialog.displayAndAwaitResult(bigtableView.getColumns()); + private void onConfigureRowValueTypes(ActionEvent event) { + BigtableValueTypesDialog.displayAndAwaitResult(bigtableTableView.getColumns()); } - private static class FetchBigtableRowsService extends Service> { - - private final BigtableClient bigtableClient; - - private BigtableReadRequest readRequest; - - public FetchBigtableRowsService(BigtableClient bigtableClient) { - this.bigtableClient = bigtableClient; - } - - public void setReadRequest(BigtableReadRequest readRequest) { - this.readRequest = readRequest; - } + private void onBigtableTableSelected(ObservableValue observable, BigtableTable oldValue, BigtableTable newValue) { - @Override - protected Task> createTask() { + bigtableTableView.clear(); + tableNameLabel.setText(newValue.getSimpleName()); + tableNameLabel.setVisible(true); + rowSelectionView.setVisible(true); - return new Task>() { - - @Override - protected List call() throws Exception { - - List rows = new LinkedList<>(); - - int count = 0; - - try(BigtableResultScanner scanner = bigtableClient.execute(readRequest)) { - - BigtableRow row = scanner.next(); + BigtableReadRequest request = new BigtableReadRequestBuilder() + .setCredentialsPath(credentialsManager.getCredentialsPath()) + .setTable(newValue) + .setRowRange(BigtableRowRange.DEFAULT) + .build(); - while (row != null) { - rows.add(row); - count++; - updateProgress(count, readRequest.getScan().getMaxRows()); - row = scanner.next(); - } - } catch (Exception e) { - e.printStackTrace(); - throw e; - } + readBigtableRows(request); + } - return rows; - } + private void readBigtableRows(BigtableReadRequest request) { + ReadBigtableRows readRowsService = new ReadBigtableRows(bigtableClient, request); + readRowsService.setOnSucceeded(workerStateEvent -> { + bigtableTableView.setVisible(true); + rowSelectionView.getProgressBar().setVisible(false); + readRowsService.getValue() + .forEach(row -> bigtableTableView.add(row)); - }; - } + }); + rowSelectionView.getProgressBar().setVisible(true); + rowSelectionView.getProgressBar().progressProperty().bind(readRowsService.progressProperty()); + readRowsService.start(); } } diff --git a/src/main/java/com/erikmafo/btviewer/controllers/MenuBarController.java b/src/main/java/com/erikmafo/btviewer/controllers/MenuBarController.java new file mode 100644 index 0000000..d75cf39 --- /dev/null +++ b/src/main/java/com/erikmafo/btviewer/controllers/MenuBarController.java @@ -0,0 +1,40 @@ +package com.erikmafo.btviewer.controllers; + +import com.erikmafo.btviewer.components.SpecifyCredentialsPathDialog; +import com.erikmafo.btviewer.services.CredentialsManager; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.MenuBar; +import javafx.scene.control.MenuItem; +import javax.inject.Inject; +import java.nio.file.Path; + +public class MenuBarController { + + private final CredentialsManager credentialsManager; + + @Inject + public MenuBarController(CredentialsManager credentialsManager) { + this.credentialsManager = credentialsManager; + } + + @FXML + private MenuItem credentialsMenu; + + @FXML + private MenuBar menuBar; + + public void initialize() { + final String os = System.getProperty("os.name"); + if (os != null && os.startsWith("Mac")) { + menuBar.useSystemMenuBarProperty().set(true); + } + } + + public void onManageCredentialsAction(ActionEvent event) { + Path currentPath = credentialsManager.getCredentialsPath(); + SpecifyCredentialsPathDialog.displayAndAwaitResult(currentPath) + .whenComplete((newCredentialsPath, throwable) -> + credentialsManager.setCredentialsPath(newCredentialsPath)); + } +} diff --git a/src/main/java/com/erikmafo/btviewer/events/BigtableProjectTreeItemExpanded.java b/src/main/java/com/erikmafo/btviewer/events/BigtableProjectTreeItemExpanded.java new file mode 100644 index 0000000..004aa63 --- /dev/null +++ b/src/main/java/com/erikmafo/btviewer/events/BigtableProjectTreeItemExpanded.java @@ -0,0 +1,23 @@ +package com.erikmafo.btviewer.events; + +import com.erikmafo.btviewer.model.BigtableInstance; +import javafx.event.Event; +import javafx.event.EventType; + +import java.util.List; + +public class BigtableProjectTreeItemExpanded extends Event { + + public static final EventType PROJECT_TREE_ITEM_EXPANDED_EVENT_TYPE = new EventType<>(EventType.ROOT); + + private final List bigtableInstances; + + public BigtableProjectTreeItemExpanded(List instances) { + super(PROJECT_TREE_ITEM_EXPANDED_EVENT_TYPE); + bigtableInstances = instances; + } + + public List getBigtableInstances() { + return bigtableInstances; + } +} diff --git a/src/main/java/com/erikmafo/btviewer/events/ScanTableAction.java b/src/main/java/com/erikmafo/btviewer/events/ScanTableAction.java new file mode 100644 index 0000000..8683bc8 --- /dev/null +++ b/src/main/java/com/erikmafo/btviewer/events/ScanTableAction.java @@ -0,0 +1,25 @@ +package com.erikmafo.btviewer.events; +import javafx.event.Event; +import javafx.event.EventType; + +public class ScanTableAction extends Event { + + public static final EventType SCAN_TABLE = new EventType<>(EventType.ROOT); + + private final String from; + private final String to; + + public ScanTableAction(String from, String to) { + super(SCAN_TABLE); + this.from = from; + this.to = to; + } + + public String getFrom() { + return from; + } + + public String getTo() { + return to; + } +} diff --git a/src/main/java/com/erikmafo/btviewer/exceptions/InvalidBigtableDefinitionException.java b/src/main/java/com/erikmafo/btviewer/exceptions/InvalidBigtableDefinitionException.java deleted file mode 100644 index 2d9e145..0000000 --- a/src/main/java/com/erikmafo/btviewer/exceptions/InvalidBigtableDefinitionException.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.erikmafo.btviewer.exceptions; - -public class InvalidBigtableDefinitionException extends Exception { - - public InvalidBigtableDefinitionException() { - } - - public InvalidBigtableDefinitionException(String message) { - super(message); - } - - public InvalidBigtableDefinitionException(String message, Throwable cause) { - super(message, cause); - } - - public InvalidBigtableDefinitionException(Throwable cause) { - super(cause); - } - - public InvalidBigtableDefinitionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/src/main/java/com/erikmafo/btviewer/model/BigtableCell.java b/src/main/java/com/erikmafo/btviewer/model/BigtableCell.java index 8b4988b..2bf51f1 100644 --- a/src/main/java/com/erikmafo/btviewer/model/BigtableCell.java +++ b/src/main/java/com/erikmafo/btviewer/model/BigtableCell.java @@ -1,6 +1,6 @@ package com.erikmafo.btviewer.model; -import com.google.protobuf.ByteString; +import com.google.bigtable.repackaged.com.google.protobuf.ByteString; public class BigtableCell { diff --git a/src/main/java/com/erikmafo/btviewer/model/BigtableInstance.java b/src/main/java/com/erikmafo/btviewer/model/BigtableInstance.java index 99b8e29..fd89aa2 100644 --- a/src/main/java/com/erikmafo/btviewer/model/BigtableInstance.java +++ b/src/main/java/com/erikmafo/btviewer/model/BigtableInstance.java @@ -6,6 +6,8 @@ public class BigtableInstance { private String projectId; + public BigtableInstance() {} + public BigtableInstance(String name) { String[] parts = name.split("/"); @@ -18,6 +20,13 @@ public BigtableInstance(String projectId, String instanceId) { this.instanceId = instanceId; } + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public void setProjectId(String projectId) { + this.projectId = projectId; + } public String getProjectId() { return projectId; diff --git a/src/main/java/com/erikmafo/btviewer/model/BigtableReadRequest.java b/src/main/java/com/erikmafo/btviewer/model/BigtableReadRequest.java index 3c227fe..08d7d25 100644 --- a/src/main/java/com/erikmafo/btviewer/model/BigtableReadRequest.java +++ b/src/main/java/com/erikmafo/btviewer/model/BigtableReadRequest.java @@ -1,19 +1,21 @@ package com.erikmafo.btviewer.model; +import java.nio.file.Path; + public class BigtableReadRequest { private final BigtableTable bigtableTable; - private final String credentialsPath; + private final Path credentialsPath; private final BigtableRowRange scan; - BigtableReadRequest(BigtableTable bigtableTable, String credentialsPath, BigtableRowRange scan) { + BigtableReadRequest(BigtableTable bigtableTable, Path credentialsPath, BigtableRowRange scan) { this.bigtableTable = bigtableTable; this.credentialsPath = credentialsPath; this.scan = scan; } - public String getCredentialsPath() { + public Path getCredentialsPath() { return credentialsPath; } diff --git a/src/main/java/com/erikmafo/btviewer/model/BigtableReadRequestBuilder.java b/src/main/java/com/erikmafo/btviewer/model/BigtableReadRequestBuilder.java index 94fafc7..c6ff875 100644 --- a/src/main/java/com/erikmafo/btviewer/model/BigtableReadRequestBuilder.java +++ b/src/main/java/com/erikmafo/btviewer/model/BigtableReadRequestBuilder.java @@ -1,22 +1,24 @@ package com.erikmafo.btviewer.model; +import java.nio.file.Path; + public class BigtableReadRequestBuilder { private BigtableTable bigtableTable; - private String credentialsPath; + private Path credentialsPath; private BigtableRowRange scan; - public BigtableReadRequestBuilder setBigtableTable(BigtableTable bigtableTable) { + public BigtableReadRequestBuilder setTable(BigtableTable bigtableTable) { this.bigtableTable = bigtableTable; return this; } - public BigtableReadRequestBuilder setCredentialsPath(String credentialsPath) { + public BigtableReadRequestBuilder setCredentialsPath(Path credentialsPath) { this.credentialsPath = credentialsPath; return this; } - public BigtableReadRequestBuilder setScan(BigtableRowRange scan) { + public BigtableReadRequestBuilder setRowRange(BigtableRowRange scan) { this.scan = scan; return this; } diff --git a/src/main/java/com/erikmafo/btviewer/model/BigtableRowRange.java b/src/main/java/com/erikmafo/btviewer/model/BigtableRowRange.java index 4057c69..81f7aaf 100644 --- a/src/main/java/com/erikmafo/btviewer/model/BigtableRowRange.java +++ b/src/main/java/com/erikmafo/btviewer/model/BigtableRowRange.java @@ -5,12 +5,14 @@ */ public class BigtableRowRange { + public static BigtableRowRange DEFAULT = new BigtableRowRange("", "~", 1000); + private final String from; private final String to; private final int maxRows; public BigtableRowRange(String from, String to) { - this(from, to, 0); + this(from, to, 1000); } public BigtableRowRange(String from, String to, int maxRows) { diff --git a/src/main/java/com/erikmafo/btviewer/model/BigtableTable.java b/src/main/java/com/erikmafo/btviewer/model/BigtableTable.java index 2bf4caf..f2961fc 100644 --- a/src/main/java/com/erikmafo/btviewer/model/BigtableTable.java +++ b/src/main/java/com/erikmafo/btviewer/model/BigtableTable.java @@ -1,5 +1,6 @@ package com.erikmafo.btviewer.model; -import com.google.cloud.bigtable.grpc.BigtableTableName; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.BigtableTableName; + import java.util.Collections; import java.util.List; diff --git a/src/main/java/com/erikmafo/btviewer/model/CellDefinition.java b/src/main/java/com/erikmafo/btviewer/model/CellDefinition.java index bb37c86..1e0821c 100644 --- a/src/main/java/com/erikmafo/btviewer/model/CellDefinition.java +++ b/src/main/java/com/erikmafo/btviewer/model/CellDefinition.java @@ -3,11 +3,6 @@ public class CellDefinition { - - public CellDefinition() { - - } - public CellDefinition(String valueType, String family, String qualifier) { this.valueType = valueType; this.family = family; @@ -18,7 +13,6 @@ public CellDefinition(String valueType, String family, String qualifier) { private String family; private String qualifier; - public String getValueType() { return valueType; } diff --git a/src/main/java/com/erikmafo/btviewer/model/CredentialsRecord.java b/src/main/java/com/erikmafo/btviewer/model/CredentialsRecord.java deleted file mode 100644 index 2e36e85..0000000 --- a/src/main/java/com/erikmafo/btviewer/model/CredentialsRecord.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.erikmafo.btviewer.model; - -import com.erikmafo.btviewer.exceptions.InvalidCredentialsRecordException; - -import java.nio.file.Path; -import java.nio.file.Paths; - -public class CredentialsRecord { - - private String projectId; - - private String instanceId; - - private Path credentialsPath; - - public String getProjectId() { - return projectId; - } - - public void setProjectId(String projectId) { - this.projectId = projectId; - } - - public String getInstanceId() { - return instanceId; - } - - public void setInstanceId(String instanceId) { - this.instanceId = instanceId; - } - - public Path getCredentialsPath() { - return credentialsPath; - } - - public void setCredentialsPath(Path credentialsPath) { - this.credentialsPath = credentialsPath; - } - - public void ensureIsValid() throws InvalidCredentialsRecordException { - - String errorMessage = null; - - if (projectId == null || projectId.isEmpty()) { - errorMessage = "Project id is not specified"; - } else if (instanceId == null || instanceId.isEmpty()) { - errorMessage = "Instance id is not specified"; - } else if (credentialsPath == null) { - errorMessage = "Credentials path is not specified"; - } else if (!credentialsPath.toFile().exists()) { - errorMessage = "Credentials path does not exist"; - } - - if (errorMessage != null) { - throw new InvalidCredentialsRecordException(errorMessage); - } - } - - public CredentialsRecordDto toDto() { - CredentialsRecordDto dto = new CredentialsRecordDto(); - dto.setCredentialsPath(credentialsPath.toFile().getPath()); - dto.setInstanceId(instanceId); - dto.setProjectId(projectId); - return dto; - } - - public static CredentialsRecord fromDto(CredentialsRecordDto dto) { - CredentialsRecord record = new CredentialsRecord(); - record.setCredentialsPath(Paths.get(dto.getCredentialsPath())); - record.setProjectId(dto.getProjectId()); - record.setInstanceId(dto.getInstanceId()); - return record; - } -} diff --git a/src/main/java/com/erikmafo/btviewer/model/CredentialsRecordDto.java b/src/main/java/com/erikmafo/btviewer/model/CredentialsRecordDto.java deleted file mode 100644 index d89c210..0000000 --- a/src/main/java/com/erikmafo/btviewer/model/CredentialsRecordDto.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.erikmafo.btviewer.model; - -public class CredentialsRecordDto { - - private String projectId; - private String instanceId; - private String credentialsPath; - - public String getProjectId() { - return projectId; - } - - public void setProjectId(String projectId) { - this.projectId = projectId; - } - - public String getInstanceId() { - return instanceId; - } - - public void setInstanceId(String instanceId) { - this.instanceId = instanceId; - } - - public String getCredentialsPath() { - return credentialsPath; - } - - public void setCredentialsPath(String credentialsPath) { - this.credentialsPath = credentialsPath; - } -} diff --git a/src/main/java/com/erikmafo/btviewer/services/BigtableClient.java b/src/main/java/com/erikmafo/btviewer/services/BigtableClient.java index f030d33..d27bac2 100644 --- a/src/main/java/com/erikmafo/btviewer/services/BigtableClient.java +++ b/src/main/java/com/erikmafo/btviewer/services/BigtableClient.java @@ -1,24 +1,25 @@ package com.erikmafo.btviewer.services; import com.erikmafo.btviewer.model.*; -import com.google.bigtable.admin.v2.ListTablesRequest; -import com.google.bigtable.admin.v2.ProjectName; -import com.google.bigtable.admin.v2.Table; -import com.google.bigtable.v2.ReadRowsRequest; -import com.google.bigtable.v2.RowRange; -import com.google.bigtable.v2.RowSet; -import com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminClient; -import com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminSettings; -import com.google.cloud.bigtable.config.BigtableOptions; -import com.google.cloud.bigtable.config.CallOptionsConfig; -import com.google.cloud.bigtable.config.CredentialOptions; -import com.google.cloud.bigtable.grpc.BigtableInstanceName; -import com.google.cloud.bigtable.grpc.BigtableSession; -import com.google.cloud.bigtable.grpc.BigtableTableAdminClient; -import com.google.protobuf.ByteString; -import java.io.FileInputStream; +import com.google.bigtable.repackaged.com.google.bigtable.admin.v2.ListTablesRequest; +import com.google.bigtable.repackaged.com.google.bigtable.admin.v2.ProjectName; +import com.google.bigtable.repackaged.com.google.bigtable.admin.v2.Table; +import com.google.bigtable.repackaged.com.google.bigtable.v2.ReadRowsRequest; +import com.google.bigtable.repackaged.com.google.bigtable.v2.RowRange; +import com.google.bigtable.repackaged.com.google.bigtable.v2.RowSet; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminClient; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.admin.v2.BigtableInstanceAdminSettings; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.config.BigtableOptions; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.config.CallOptionsConfig; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.config.CredentialOptions; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.BigtableInstanceName; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.BigtableSession; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.BigtableTableAdminClient; +import com.google.bigtable.repackaged.com.google.protobuf.ByteString; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -30,23 +31,21 @@ */ public class BigtableClient { - private Map credentialOptionsCache = new ConcurrentHashMap<>(); - public static final Charset DEFAULT_CHARSET = Charset.defaultCharset(); + private final Map credentialOptionsCache = new ConcurrentHashMap<>(); + private static final Charset DEFAULT_CHARSET = Charset.defaultCharset(); - private CredentialOptions getCredentialOptions(String credentialsPath) throws IOException { + private CredentialOptions getCredentialOptions(Path credentialsPath) throws IOException { if (credentialsPath == null) { return CredentialOptions.defaultCredentials(); } - if (credentialOptionsCache.containsKey(credentialsPath)) { - return credentialOptionsCache.get(credentialsPath); + if (credentialOptionsCache.containsKey(credentialsPath.toString())) { + return credentialOptionsCache.get(credentialsPath.toString()); } - CredentialOptions credentialOptions = CredentialOptions.jsonCredentials(new FileInputStream(credentialsPath)); - - credentialOptionsCache.put(credentialsPath, credentialOptions); - + CredentialOptions credentialOptions = CredentialOptions.jsonCredentials(Files.newInputStream(credentialsPath)); + credentialOptionsCache.put(credentialsPath.toString(), credentialOptions); return credentialOptions; } @@ -54,7 +53,7 @@ public BigtableResultScanner execute(BigtableReadRequest bigtableReadRequest) th BigtableTable bigtableTable = bigtableReadRequest.getBigtableTable(); BigtableRowRange bigtableRowRange = bigtableReadRequest.getScan(); - String credentialsPath = bigtableReadRequest.getCredentialsPath(); + Path credentialsPath = bigtableReadRequest.getCredentialsPath(); BigtableSession bigtableSession = getBigtableSession( bigtableTable.getProjectId(), @@ -83,7 +82,7 @@ public BigtableResultScanner execute(BigtableReadRequest bigtableReadRequest) th } - public List listTables(BigtableInstance bigtableInstance, String credentialsPath) throws IOException { + public List listTables(BigtableInstance bigtableInstance, Path credentialsPath) throws IOException { try (BigtableSession session = getBigtableSession( bigtableInstance.getProjectId(), bigtableInstance.getInstanceId(), @@ -117,7 +116,7 @@ public List listInstances(String projectId, String credentials } - private BigtableSession getBigtableSession(String projectId, String instanceId, String credentialsPath) throws IOException { + private BigtableSession getBigtableSession(String projectId, String instanceId, Path credentialsPath) throws IOException { BigtableOptions googleBigtableOptions = BigtableOptions.builder() diff --git a/src/main/java/com/erikmafo/btviewer/services/BigtableInstanceManager.java b/src/main/java/com/erikmafo/btviewer/services/BigtableInstanceManager.java new file mode 100644 index 0000000..445f681 --- /dev/null +++ b/src/main/java/com/erikmafo/btviewer/services/BigtableInstanceManager.java @@ -0,0 +1,56 @@ +package com.erikmafo.btviewer.services; + +import com.erikmafo.btviewer.model.BigtableInstance; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.prefs.Preferences; + +public class BigtableInstanceManager { + + private static final Type LIST_TYPE = new TypeToken>() {}.getType(); + private static final String PREFERENCES_USER_ROOT_NODE_NAME = "bigtable-viewer-configs"; + private static final String INSTANCES = "instances"; + + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + private final Object mutex = new Object(); + + private final Gson gson = new Gson(); + private List bigtableInstances; + + public BigtableInstanceManager() { + String json = getPreferences().get(INSTANCES, null); + if (json != null) { + bigtableInstances = gson.fromJson(json, LIST_TYPE); + } + else { + bigtableInstances = new ArrayList<>(); + } + } + + public List getInstances() { + synchronized (mutex) { + return bigtableInstances; + } + } + + public void setInstances(List instances) { + + synchronized (mutex) { + this.bigtableInstances = instances; + executorService.submit(() -> { + String json = gson.toJson(instances, LIST_TYPE); + getPreferences().put(INSTANCES, json); + }); + } + } + + private Preferences getPreferences() { + return Preferences.userRoot().node(PREFERENCES_USER_ROOT_NODE_NAME); + } +} diff --git a/src/main/java/com/erikmafo/btviewer/services/BigtableResultScanner.java b/src/main/java/com/erikmafo/btviewer/services/BigtableResultScanner.java index ac16583..d0a54b0 100644 --- a/src/main/java/com/erikmafo/btviewer/services/BigtableResultScanner.java +++ b/src/main/java/com/erikmafo/btviewer/services/BigtableResultScanner.java @@ -3,9 +3,9 @@ import com.erikmafo.btviewer.model.BigtableCell; import com.erikmafo.btviewer.model.BigtableRow; import com.erikmafo.btviewer.model.CellDefinition; -import com.google.cloud.bigtable.grpc.BigtableSession; -import com.google.cloud.bigtable.grpc.scanner.FlatRow; -import com.google.cloud.bigtable.grpc.scanner.ResultScanner; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.BigtableSession; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.scanner.FlatRow; +import com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.scanner.ResultScanner; import java.io.Closeable; import java.io.IOException; diff --git a/src/main/java/com/erikmafo/btviewer/services/CredentialsManager.java b/src/main/java/com/erikmafo/btviewer/services/CredentialsManager.java new file mode 100644 index 0000000..5711003 --- /dev/null +++ b/src/main/java/com/erikmafo/btviewer/services/CredentialsManager.java @@ -0,0 +1,57 @@ +package com.erikmafo.btviewer.services; +import java.nio.file.Path; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.prefs.Preferences; + +/** + * Created by erikmafo on 25.12.17. + */ +public class CredentialsManager { + + private static final String PREFERENCES_USER_ROOT_NODE_NAME = "bigtable-viewer-configs"; + private static final String CREDENTIALS_PATH = "credentials-path"; + + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + private final Object mutex = new Object(); + + private Path credentialsPath; + + public CredentialsManager() { + String pathAsString = getPreferences().get(CREDENTIALS_PATH, null); + + if (pathAsString != null) { + credentialsPath = Path.of(pathAsString); + } + } + + public void setCredentialsPath(Path credentialsPath) { + + if (credentialsPath == null) { + return; + } + + synchronized (mutex) { + if (credentialsPath.equals(this.credentialsPath)) { + return; + } + this.credentialsPath = credentialsPath; + executorService.submit(() -> getPreferences().put(CREDENTIALS_PATH, credentialsPath.toString())); + } + } + + public Path getCredentialsPath() { + + synchronized (mutex) { + if (credentialsPath != null) { + return credentialsPath; + } else { + return null; + } + } + } + + private Preferences getPreferences() { + return Preferences.userRoot().node(PREFERENCES_USER_ROOT_NODE_NAME); + } +} diff --git a/src/main/java/com/erikmafo/btviewer/services/ListBigtableTables.java b/src/main/java/com/erikmafo/btviewer/services/ListBigtableTables.java new file mode 100644 index 0000000..9841534 --- /dev/null +++ b/src/main/java/com/erikmafo/btviewer/services/ListBigtableTables.java @@ -0,0 +1,42 @@ +package com.erikmafo.btviewer.services; + +import com.erikmafo.btviewer.model.BigtableInstance; +import com.erikmafo.btviewer.model.BigtableTable; +import javafx.concurrent.Service; +import javafx.concurrent.Task; + +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; + +public class ListBigtableTables extends Service> { + + private final BigtableClient client; + private final BigtableInstance instance; + private final Path credentialsPath; + + public ListBigtableTables(BigtableClient client, BigtableInstance instance, Path credentialsPath) { + this.client = client; + this.instance = instance; + this.credentialsPath = credentialsPath; + } + + @Override + protected Task> createTask() { + return new Task>() { + @Override + protected List call() throws Exception { + return client.listTables( + instance, + credentialsPath) + .stream() + .map(ListBigtableTables.this::getBigtableTable) + .collect(Collectors.toList()); + } + }; + } + + private BigtableTable getBigtableTable(String tableName) { + return new BigtableTable(tableName); + } +} diff --git a/src/main/java/com/erikmafo/btviewer/services/ReadBigtableRows.java b/src/main/java/com/erikmafo/btviewer/services/ReadBigtableRows.java new file mode 100644 index 0000000..c8a7421 --- /dev/null +++ b/src/main/java/com/erikmafo/btviewer/services/ReadBigtableRows.java @@ -0,0 +1,46 @@ +package com.erikmafo.btviewer.services; + +import com.erikmafo.btviewer.model.*; +import javafx.concurrent.Service; +import javafx.concurrent.Task; +import java.util.ArrayList; +import java.util.List; + +public class ReadBigtableRows extends Service> { + + private final BigtableClient client; + private final BigtableReadRequest readRequest; + + public ReadBigtableRows(BigtableClient client, BigtableReadRequest readRequest) { + this.client = client; + this.readRequest = readRequest; + } + + @Override + protected Task> createTask() { + return new Task<>() { + @Override + protected List call() throws Exception { + + try (BigtableResultScanner scanner = client.execute(readRequest)) { + List result = new ArrayList<>(); + int count = 0; + BigtableRow row; + do { + count++; + row = scanner.next(); + if (row == null) { + break; + } + result.add(row); + updateProgress(count, readRequest.getScan().getMaxRows()); + + } while (count < readRequest.getScan().getMaxRows()); + return result; + } + } + }; + } +} + + diff --git a/src/main/java/com/erikmafo/btviewer/services/UserConfigurationService.java b/src/main/java/com/erikmafo/btviewer/services/UserConfigurationService.java deleted file mode 100644 index 9b2d206..0000000 --- a/src/main/java/com/erikmafo/btviewer/services/UserConfigurationService.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.erikmafo.btviewer.services; -import com.erikmafo.btviewer.model.*; -import com.google.gson.*; -import com.google.gson.reflect.TypeToken; - -import java.lang.reflect.Type; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.prefs.Preferences; -import java.util.stream.Collectors; - -/** - * Created by erikmafo on 25.12.17. - */ -public class UserConfigurationService { - - private static final String PREFERENCES_USER_ROOT_NODE_NAME = "bigtable-viewer-configs"; - private static final String BIGTABLE_TABLE_DEFINITIONS = "bigtable-table-definitions"; - private static final String CREDENTIAL_RECORDS = "credential-records"; - private static final String CREDENTIALS_PATH = "credentials-path"; - - private final Gson gson = new Gson(); - - public String getCredentialsPath() { - return getPreferences().get(CREDENTIALS_PATH, null); - } - - public void setCredentialsPath(String credentialsPath) { - getPreferences().put(CREDENTIALS_PATH, credentialsPath); - } - - public void updateBigtableDefinitions(List bigtableOptions) { - - String json = gson.toJson(bigtableOptions); - - getPreferences().put(BIGTABLE_TABLE_DEFINITIONS, json); - } - - public List loadBigtableDefinitions() { - - Preferences prefs = getPreferences(); - - String json = prefs.get(BIGTABLE_TABLE_DEFINITIONS, null); - - if (json == null) { - return Collections.emptyList(); - } - - Type listType = new TypeToken>() { - }.getType(); - - - try { - return gson.fromJson(json, listType); - } catch (Exception ex) { - Logger.getLogger(UserConfigurationService.class.getName()).log(Level.WARNING, "Unable to read bigtable options", ex); - return Collections.emptyList(); - } - } - - - public List loadCredentialRecords() { - - String json = getPreferences().get(CREDENTIAL_RECORDS, null); - - if (json == null) { - return Collections.emptyList(); - } - - Type listType = new TypeToken>() {}.getType(); - - List dtos = gson.fromJson(json, listType); - - if (dtos == null) { - return Collections.emptyList(); - } - - return dtos.stream().map(CredentialsRecord::fromDto).collect(Collectors.toList()); - } - - - public void updateCredentialRecords(List records) { - - List dtos = records.stream().map(CredentialsRecord::toDto).collect(Collectors.toList()); - - String json = gson.toJson(dtos); - - getPreferences().put(CREDENTIAL_RECORDS, json); - } - - private Preferences getPreferences() { - return Preferences.userRoot().node(PREFERENCES_USER_ROOT_NODE_NAME); - } - -} diff --git a/src/main/resources/css/main.css b/src/main/resources/css/main.css index 3fb7f5f..8b13789 100644 --- a/src/main/resources/css/main.css +++ b/src/main/resources/css/main.css @@ -1,33 +1 @@ -.root { - -fx-pref-height: 600.0; - -fx-pref-width: 700.0; -} - -.title { - -fx-font-size: 14; - -fx-font-name: "System Bold"; - -fx-alignment: "CENTER"; - -fx-padding: 10 20 10 20; -} - -.tableTitleHBox { - -fx-alignment: "CENTER"; - -fx-spacing: 3; -} - -.tableTitleHBox .button { - -fx-font-size: 9; -} - -.scanTableControls { - -fx-alignment: "CENTER"; - -fx-hgap: 5; - -fx-vgap: 5; -} - -.scanTableControls .hBox { - -fx-spacing: 0 -} - - diff --git a/src/main/resources/fxml/bigtable_instance_dialog.fxml b/src/main/resources/fxml/bigtable_instance_dialog.fxml index 1d54421..b53d6cb 100644 --- a/src/main/resources/fxml/bigtable_instance_dialog.fxml +++ b/src/main/resources/fxml/bigtable_instance_dialog.fxml @@ -3,7 +3,6 @@ diff --git a/src/main/resources/fxml/bigtable_menu_bar.fxml b/src/main/resources/fxml/bigtable_menu_bar.fxml index df49b62..9090863 100644 --- a/src/main/resources/fxml/bigtable_menu_bar.fxml +++ b/src/main/resources/fxml/bigtable_menu_bar.fxml @@ -4,16 +4,13 @@ - - - + - - - + @@ -22,8 +19,6 @@ - - diff --git a/src/main/resources/fxml/bigtable_table_view.fxml b/src/main/resources/fxml/bigtable_table_view.fxml new file mode 100644 index 0000000..2995177 --- /dev/null +++ b/src/main/resources/fxml/bigtable_table_view.fxml @@ -0,0 +1,14 @@ + + + + + + + + + - - - + \ No newline at end of file diff --git a/src/main/resources/fxml/bigtable_value_types_dialog.fxml b/src/main/resources/fxml/bigtable_value_types_dialog.fxml index 179cc8d..4b561b3 100644 --- a/src/main/resources/fxml/bigtable_value_types_dialog.fxml +++ b/src/main/resources/fxml/bigtable_value_types_dialog.fxml @@ -12,7 +12,13 @@ - + diff --git a/src/main/resources/fxml/bigtable_view.fxml b/src/main/resources/fxml/bigtable_view.fxml deleted file mode 100644 index 8c165d8..0000000 --- a/src/main/resources/fxml/bigtable_view.fxml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/main/resources/fxml/edit_single_credentials_dialog_pane.fxml b/src/main/resources/fxml/edit_single_credentials_dialog_pane.fxml deleted file mode 100644 index 9e52fbe..0000000 --- a/src/main/resources/fxml/edit_single_credentials_dialog_pane.fxml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - -