Skip to content

Commit

Permalink
Add expert mode for shared database connection (#11303)
Browse files Browse the repository at this point in the history
* Add expert mode for shared database connection
allows entering a custom jdbc url

Add lib for socket connection factory

* checkstyle

* checkstyle
  • Loading branch information
Siedlerchr authored Jun 17, 2024
1 parent d51b52b commit 77c5188
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 20 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ dependencies {

implementation 'org.postgresql:postgresql:42.7.3'

// Support unix socket connection types
implementation 'com.kohlschutter.junixsocket:junixsocket-core:2.9.1'
implementation 'com.kohlschutter.junixsocket:junixsocket-mysql:2.9.1'

implementation ('com.oracle.ojdbc:ojdbc10:19.3.0.0') {
// causing module issues
exclude module: 'oraclepki'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
<RowConstraints minHeight="10.0" prefHeight="30.0"/>
<RowConstraints minHeight="10.0" prefHeight="30.0"/>
<RowConstraints minHeight="10.0" prefHeight="30.0"/>
<RowConstraints minHeight="10.0" prefHeight="30.0"/>
<RowConstraints minHeight="10.0" prefHeight="30.0"/>
<RowConstraints/>
</rowConstraints>
<children>
Expand Down Expand Up @@ -67,6 +69,11 @@
<Label text="%Server Timezone:" GridPane.rowIndex="8"/>
<TextField fx:id="serverTimezone" GridPane.columnIndex="1" GridPane.columnSpan="2"
GridPane.rowIndex="8"/>
<Label text="%Server Timezone:" GridPane.rowIndex="8"/>
<CheckBox fx:id="expertMode" mnemonicParsing="false" text="%Use Expert mode" GridPane.rowIndex="9"/>
<Label text="%Custom JDBC Url:" GridPane.rowIndex="10"/>
<TextField fx:id="jdbcUrl" GridPane.columnIndex="1" GridPane.columnSpan="2"
GridPane.rowIndex="10"/>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public class SharedDatabaseLoginDialogView extends BaseDialog<Void> {
@FXML private PasswordField passwordKeystore;
@FXML private Button browseKeystore;
@FXML private TextField serverTimezone;
@FXML private TextField jdbcUrl;
@FXML private CheckBox expertMode;

@Inject private DialogService dialogService;
@Inject private PreferencesService preferencesService;
Expand Down Expand Up @@ -117,6 +119,10 @@ private void initialize() {

fileKeystore.textProperty().bindBidirectional(viewModel.keyStoreProperty());

expertMode.selectedProperty().bindBidirectional(viewModel.expertModeProperty());
jdbcUrl.textProperty().bindBidirectional(viewModel.jdbcUrlProperty());
jdbcUrl.disableProperty().bind(viewModel.expertModeProperty().not());

browseKeystore.disableProperty().bind(viewModel.useSSLProperty().not());
passwordKeystore.disableProperty().bind(viewModel.useSSLProperty().not());
passwordKeystore.textProperty().bindBidirectional(viewModel.keyStorePasswordProperty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public class SharedDatabaseLoginDialogViewModel extends AbstractViewModel {
private final BooleanProperty useSSL = new SimpleBooleanProperty();
private final StringProperty keyStorePasswordProperty = new SimpleStringProperty("");
private final StringProperty serverTimezone = new SimpleStringProperty("");
private final BooleanProperty expertMode = new SimpleBooleanProperty();
private final StringProperty jdbcUrl = new SimpleStringProperty("");

private final LibraryTabContainer tabContainer;
private final DialogService dialogService;
Expand Down Expand Up @@ -144,6 +146,8 @@ public boolean openDatabase() {
.setAllowPublicKeyRetrieval(true)
.setKeyStore(keystore.getValue())
.setServerTimezone(serverTimezone.getValue())
.setExpertMode(expertMode.getValue())
.setJdbcUrl(jdbcUrl.getValue())
.createDBMSConnectionProperties();

setupKeyStore();
Expand Down Expand Up @@ -403,4 +407,12 @@ public ValidationStatus formValidation() {
public StringProperty serverTimezoneProperty() {
return serverTimezone;
}

public BooleanProperty expertModeProperty() {
return expertMode;
}

public StringProperty jdbcUrlProperty() {
return jdbcUrl;
}
}
9 changes: 7 additions & 2 deletions src/main/java/org/jabref/logic/shared/DBMSConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@ public DBMSConnection(DBMSConnectionProperties connectionProperties) throws SQLE
// ensure that all SQL drivers are loaded - source: http://stackoverflow.com/a/22384826/873282
// we use the side effect of getAvailableDBMSTypes() - it loads all available drivers
DBMSConnection.getAvailableDBMSTypes();
this.connection = DriverManager.getConnection(connectionProperties.getUrl(), connectionProperties.asProperties());

if (connectionProperties.isUseExpertMode()) {
this.connection = DriverManager.getConnection(connectionProperties.getJdbcUrl(), connectionProperties.asProperties());
} else {
this.connection = DriverManager.getConnection(connectionProperties.getUrl(), connectionProperties.asProperties());
}
} catch (SQLException e) {
// Some systems like PostgreSQL retrieves 0 to every exception.
// Therefore a stable error determination is not possible.
LOGGER.error("Could not connect to database: " + e.getMessage() + " - Error code: " + e.getErrorCode());
LOGGER.error("Could not connect to database: {} - Error code: {}", e.getMessage(), e.getErrorCode());
throw e;
}
}
Expand Down
47 changes: 32 additions & 15 deletions src/main/java/org/jabref/logic/shared/DBMSConnectionProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ public class DBMSConnectionProperties implements DatabaseConnectionProperties {
private String user;
private String password;
private boolean allowPublicKeyRetrieval;
private boolean useSSL;
private final boolean useSSL;
private String serverTimezone = "";
private String jdbcUrl = "";
private final boolean expertMode;

// Not needed for connection, but stored for future login
private String keyStore;
Expand All @@ -38,16 +40,17 @@ public class DBMSConnectionProperties implements DatabaseConnectionProperties {
public DBMSConnectionProperties(SharedDatabasePreferences prefs) {
if (prefs.getType().isPresent()) {
Optional<DBMSType> dbmsType = DBMSType.fromString(prefs.getType().get());
if (dbmsType.isPresent()) {
this.type = dbmsType.get();
}
dbmsType.ifPresent(value -> this.type = value);
}

prefs.getHost().ifPresent(theHost -> this.host = theHost);
prefs.getPort().ifPresent(thePort -> this.port = Integer.parseInt(thePort));
prefs.getName().ifPresent(theDatabase -> this.database = theDatabase);
prefs.getKeyStoreFile().ifPresent(theKeystore -> this.keyStore = theKeystore);
prefs.getServerTimezone().ifPresent(theServerTimezone -> this.serverTimezone = theServerTimezone);
prefs.getJdbcUrl().ifPresent(theJdbcUrl -> this.jdbcUrl = theJdbcUrl);

this.expertMode = prefs.isUseExpertMode();
this.useSSL = prefs.isUseSSL();

if (prefs.getUser().isPresent()) {
Expand All @@ -61,14 +64,15 @@ public DBMSConnectionProperties(SharedDatabasePreferences prefs) {
}
}

if (!prefs.getPassword().isPresent()) {
if (prefs.getPassword().isEmpty()) {
// Some DBMS require a non-null value as a password (in case of using an empty string).
this.password = "";
}
}

DBMSConnectionProperties(DBMSType type, String host, int port, String database, String user,
String password, boolean useSSL, boolean allowPublicKeyRetrieval, String serverTimezone, String keyStore) {
String password, boolean useSSL, boolean allowPublicKeyRetrieval,
String serverTimezone, String keyStore, String jdbcUrl, boolean expertMode) {
this.type = type;
this.host = host;
this.port = port;
Expand All @@ -79,6 +83,8 @@ public DBMSConnectionProperties(SharedDatabasePreferences prefs) {
this.allowPublicKeyRetrieval = allowPublicKeyRetrieval;
this.serverTimezone = serverTimezone;
this.keyStore = keyStore;
this.jdbcUrl = jdbcUrl;
this.expertMode = expertMode;
}

@Override
Expand Down Expand Up @@ -126,9 +132,18 @@ public String getServerTimezone() {
return serverTimezone;
}

@Override
public String getJdbcUrl() {
return jdbcUrl;
}

@Override
public boolean isUseExpertMode() {
return expertMode;
}

public String getUrl() {
String url = type.getUrl(host, port, database);
return url;
return type.getUrl(host, port, database);
}

/**
Expand All @@ -142,11 +157,11 @@ public Properties asProperties() {
props.setProperty("password", password);
props.setProperty("serverTimezone", serverTimezone);
if (useSSL) {
props.setProperty("ssl", Boolean.toString(useSSL));
props.setProperty("useSSL", Boolean.toString(useSSL));
props.setProperty("ssl", Boolean.toString(true));
props.setProperty("useSSL", Boolean.toString(true));
}
if (allowPublicKeyRetrieval) {
props.setProperty("allowPublicKeyRetrieval", Boolean.toString(allowPublicKeyRetrieval));
props.setProperty("allowPublicKeyRetrieval", Boolean.toString(true));
}
return props;
}
Expand All @@ -165,23 +180,25 @@ public boolean equals(Object obj) {
return true;
}

if (!(obj instanceof DBMSConnectionProperties)) {
if (!(obj instanceof DBMSConnectionProperties properties)) {
return false;
}
DBMSConnectionProperties properties = (DBMSConnectionProperties) obj;
return Objects.equals(type, properties.getType())
&& this.host.equalsIgnoreCase(properties.getHost())
&& Objects.equals(port, properties.getPort())
&& Objects.equals(database, properties.getDatabase())
&& Objects.equals(user, properties.getUser())
&& Objects.equals(useSSL, properties.isUseSSL())
&& Objects.equals(allowPublicKeyRetrieval, properties.isAllowPublicKeyRetrieval())
&& Objects.equals(serverTimezone, properties.getServerTimezone());
&& Objects.equals(serverTimezone, properties.getServerTimezone())
&& Objects.equals(keyStore, properties.getKeyStore())
&& Objects.equals(jdbcUrl, properties.getJdbcUrl())
&& Objects.equals(expertMode, properties.isUseExpertMode());
}

@Override
public int hashCode() {
return Objects.hash(type, host, port, database, user, useSSL);
return Objects.hash(type, host, port, database, user, useSSL, allowPublicKeyRetrieval, serverTimezone, keyStore, jdbcUrl, expertMode);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class DBMSConnectionPropertiesBuilder {
private boolean allowPublicKeyRetrieval;
private String serverTimezone = "";
private String keyStore;
private boolean expertMode = false;
private String jdbcUrl = "";

public DBMSConnectionPropertiesBuilder setType(DBMSType type) {
this.type = type;
Expand Down Expand Up @@ -62,10 +64,20 @@ public DBMSConnectionPropertiesBuilder setKeyStore(String keyStore) {
return this;
}

public DBMSConnectionPropertiesBuilder setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
return this;
}

public DBMSConnectionPropertiesBuilder setExpertMode(boolean expertMode) {
this.expertMode = expertMode;
return this;
}

public DBMSConnectionProperties createDBMSConnectionProperties() {
if (port == -1) {
port = type.getDefaultPort();
}
return new DBMSConnectionProperties(type, host, port, database, user, password, useSSL, allowPublicKeyRetrieval, serverTimezone, keyStore);
return new DBMSConnectionProperties(type, host, port, database, user, password, useSSL, allowPublicKeyRetrieval, serverTimezone, keyStore, jdbcUrl, expertMode);
}
}
4 changes: 2 additions & 2 deletions src/main/java/org/jabref/logic/shared/DBMSType.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ public enum DBMSType {

private final String type;
private final String driverPath;
private final String urlPattern;
private String urlPattern;
private final int defaultPort;

private DBMSType(String type, String driverPath, String urlPattern, int defaultPort) {
DBMSType(String type, String driverPath, String urlPattern, int defaultPort) {
this.type = type;
this.driverPath = driverPath;
this.urlPattern = urlPattern;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ public interface DatabaseConnectionProperties {
boolean isAllowPublicKeyRetrieval();

String getServerTimezone();

String getJdbcUrl();

boolean isUseExpertMode();
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class SharedDatabasePreferences {
private static final String SHARED_DATABASE_USE_SSL = "sharedDatabaseUseSSL";
private static final String SHARED_DATABASE_KEYSTORE_FILE = "sharedDatabaseKeyStoreFile";
private static final String SHARED_DATABASE_SERVER_TIMEZONE = "sharedDatabaseServerTimezone";
private static final String SHARED_DATABASE_EXPERT_MODE = "sharedDatabaseExpertMode";
private static final String SHARED_DATABASE_JDBC_URL = "sharedDatabaseJdbcUrl";

// This {@link Preferences} is used only for things which should not appear in real JabRefPreferences due to security reasons.
private final Preferences internalPrefs;
Expand Down Expand Up @@ -143,6 +145,22 @@ public void clearPassword() {
internalPrefs.remove(SHARED_DATABASE_PASSWORD);
}

public void setExpertMode(boolean expertMode) {
internalPrefs.putBoolean(SHARED_DATABASE_EXPERT_MODE, expertMode);
}

public void setJdbcUrl(String jdbcUrl) {
internalPrefs.put(SHARED_DATABASE_JDBC_URL, jdbcUrl);
}

public boolean isUseExpertMode() {
return internalPrefs.getBoolean(SHARED_DATABASE_EXPERT_MODE, false);
}

public Optional<String> getJdbcUrl() {
return getOptionalValue(SHARED_DATABASE_JDBC_URL);
}

public void clear() throws BackingStoreException {
internalPrefs.clear();
}
Expand All @@ -166,6 +184,8 @@ public void putAllDBMSConnectionProperties(DatabaseConnectionProperties properti
setUseSSL(properties.isUseSSL());
setKeystoreFile(properties.getKeyStore());
setServerTimezone(properties.getServerTimezone());
setExpertMode(properties.isUseExpertMode());
setJdbcUrl(properties.getJdbcUrl());

try {
setPassword(new Password(properties.getPassword().toCharArray(), properties.getUser()).encrypt());
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,9 @@ Open\ last\ edited\ libraries\ on\ startup=Open last edited libraries on startup

Connect\ to\ shared\ database=Connect to shared database

Use\ Expert\ mode=Use Expert mode
Custom\ JDBC\ Url\:=Custom JDBC Url:

Open\ terminal\ here=Open terminal here

Open\ URL\ or\ DOI=Open URL or DOI
Expand Down

0 comments on commit 77c5188

Please sign in to comment.