Cleaned up profile loading exceptions.

This commit is contained in:
Andrew Lalis 2024-01-03 15:20:34 -05:00
parent 48dc4fd9e7
commit a7654e49ca
8 changed files with 53 additions and 37 deletions

View File

@ -2,8 +2,7 @@ package com.andrewlalis.perfin;
import com.andrewlalis.javafx_scene_router.AnchorPaneRouterView; import com.andrewlalis.javafx_scene_router.AnchorPaneRouterView;
import com.andrewlalis.javafx_scene_router.SceneRouter; import com.andrewlalis.javafx_scene_router.SceneRouter;
import com.andrewlalis.perfin.control.Popups; import com.andrewlalis.perfin.data.ProfileLoadException;
import com.andrewlalis.perfin.data.DataSourceInitializationException;
import com.andrewlalis.perfin.model.Profile; import com.andrewlalis.perfin.model.Profile;
import com.andrewlalis.perfin.view.ImageCache; import com.andrewlalis.perfin.view.ImageCache;
import com.andrewlalis.perfin.view.SceneUtil; import com.andrewlalis.perfin.view.SceneUtil;
@ -93,8 +92,8 @@ public class PerfinApp extends Application {
msgConsumer.accept("Loading the most recent profile."); msgConsumer.accept("Loading the most recent profile.");
try { try {
Profile.loadLast(); Profile.loadLast();
} catch (DataSourceInitializationException e) { } catch (ProfileLoadException e) {
Popups.error(e.getMessage()); msgConsumer.accept("Failed to load the profile: " + e.getMessage());
throw e; throw e;
} }
} }

View File

@ -1,7 +1,7 @@
package com.andrewlalis.perfin.control; package com.andrewlalis.perfin.control;
import com.andrewlalis.perfin.PerfinApp; import com.andrewlalis.perfin.PerfinApp;
import com.andrewlalis.perfin.data.DataSourceInitializationException; import com.andrewlalis.perfin.data.ProfileLoadException;
import com.andrewlalis.perfin.data.util.FileUtil; import com.andrewlalis.perfin.data.util.FileUtil;
import com.andrewlalis.perfin.model.Profile; import com.andrewlalis.perfin.model.Profile;
import com.andrewlalis.perfin.view.ProfilesStage; import com.andrewlalis.perfin.view.ProfilesStage;
@ -121,12 +121,8 @@ public class ProfilesViewController {
router.navigate("accounts"); router.navigate("accounts");
if (showPopup) Popups.message("The profile \"" + name + "\" has been loaded."); if (showPopup) Popups.message("The profile \"" + name + "\" has been loaded.");
return true; return true;
} catch (IOException e) { } catch (ProfileLoadException e) {
e.printStackTrace(System.err); Popups.error("Failed to load the profile: " + e.getMessage());
Popups.error("Failed to load profile: " + e.getMessage());
return false;
} catch (DataSourceInitializationException e) {
Popups.error("Failed to initialize the profile's data: " + e.getMessage());
return false; return false;
} }
} }

View File

@ -1,11 +0,0 @@
package com.andrewlalis.perfin.data;
public class DataSourceInitializationException extends Exception {
public DataSourceInitializationException(String message) {
super(message);
}
public DataSourceInitializationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,11 @@
package com.andrewlalis.perfin.data;
public class ProfileLoadException extends Exception {
public ProfileLoadException(String message) {
super(message);
}
public ProfileLoadException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,7 +1,7 @@
package com.andrewlalis.perfin.data.impl; package com.andrewlalis.perfin.data.impl;
import com.andrewlalis.perfin.data.DataSource; import com.andrewlalis.perfin.data.DataSource;
import com.andrewlalis.perfin.data.DataSourceInitializationException; import com.andrewlalis.perfin.data.ProfileLoadException;
import com.andrewlalis.perfin.data.util.FileUtil; import com.andrewlalis.perfin.data.util.FileUtil;
import com.andrewlalis.perfin.model.Profile; import com.andrewlalis.perfin.model.Profile;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -32,7 +32,7 @@ public class JdbcDataSourceFactory {
*/ */
public static final int SCHEMA_VERSION = 1; public static final int SCHEMA_VERSION = 1;
public DataSource getDataSource(String profileName) throws DataSourceInitializationException { public DataSource getDataSource(String profileName) throws ProfileLoadException {
final boolean dbExists = Files.exists(getDatabaseFile(profileName)); final boolean dbExists = Files.exists(getDatabaseFile(profileName));
if (!dbExists) { if (!dbExists) {
log.info("Creating new database for profile {}.", profileName); log.info("Creating new database for profile {}.", profileName);
@ -43,7 +43,7 @@ public class JdbcDataSourceFactory {
loadedSchemaVersion = getSchemaVersion(profileName); loadedSchemaVersion = getSchemaVersion(profileName);
} catch (IOException e) { } catch (IOException e) {
log.error("Failed to load schema version.", e); log.error("Failed to load schema version.", e);
throw new DataSourceInitializationException("Failed to determine database schema version.", e); throw new ProfileLoadException("Failed to determine database schema version.", e);
} }
log.debug("Database loaded for profile {} has schema version {}.", profileName, loadedSchemaVersion); log.debug("Database loaded for profile {} has schema version {}.", profileName, loadedSchemaVersion);
if (loadedSchemaVersion < SCHEMA_VERSION) { if (loadedSchemaVersion < SCHEMA_VERSION) {
@ -51,13 +51,13 @@ public class JdbcDataSourceFactory {
// TODO: Do migration // TODO: Do migration
} else if (loadedSchemaVersion > SCHEMA_VERSION) { } else if (loadedSchemaVersion > SCHEMA_VERSION) {
log.debug("Schema version {} is higher than the app's version {}. Cannot continue.", loadedSchemaVersion, SCHEMA_VERSION); log.debug("Schema version {} is higher than the app's version {}. Cannot continue.", loadedSchemaVersion, SCHEMA_VERSION);
throw new DataSourceInitializationException("Profile " + profileName + " has a database with an unsupported schema version."); throw new ProfileLoadException("Profile " + profileName + " has a database with an unsupported schema version.");
} }
} }
return new JdbcDataSource(getJdbcUrl(profileName), Profile.getContentDir(profileName)); return new JdbcDataSource(getJdbcUrl(profileName), Profile.getContentDir(profileName));
} }
private void createNewDatabase(String profileName) throws DataSourceInitializationException { private void createNewDatabase(String profileName) throws ProfileLoadException {
log.info("Creating new database for profile {}.", profileName); log.info("Creating new database for profile {}.", profileName);
JdbcDataSource dataSource = new JdbcDataSource(getJdbcUrl(profileName), Profile.getContentDir(profileName)); JdbcDataSource dataSource = new JdbcDataSource(getJdbcUrl(profileName), Profile.getContentDir(profileName));
try ( try (
@ -81,15 +81,15 @@ public class JdbcDataSourceFactory {
} catch (IOException e) { } catch (IOException e) {
log.error("IO Exception when trying to create database.", e); log.error("IO Exception when trying to create database.", e);
FileUtil.deleteIfPossible(getDatabaseFile(profileName)); FileUtil.deleteIfPossible(getDatabaseFile(profileName));
throw new DataSourceInitializationException("Failed to read SQL data to create database schema.", e); throw new ProfileLoadException("Failed to read SQL data to create database schema.", e);
} catch (SQLException e) { } catch (SQLException e) {
log.error("SQL Exception when trying to create database.", e); log.error("SQL Exception when trying to create database.", e);
FileUtil.deleteIfPossible(getDatabaseFile(profileName)); FileUtil.deleteIfPossible(getDatabaseFile(profileName));
throw new DataSourceInitializationException("Failed to create the database due to an SQL error.", e); throw new ProfileLoadException("Failed to create the database due to an SQL error.", e);
} }
if (!testConnection(dataSource)) { if (!testConnection(dataSource)) {
FileUtil.deleteIfPossible(getDatabaseFile(profileName)); FileUtil.deleteIfPossible(getDatabaseFile(profileName));
throw new DataSourceInitializationException("Testing the database connection failed."); throw new ProfileLoadException("Testing the database connection failed.");
} }
} }
@ -117,7 +117,11 @@ public class JdbcDataSourceFactory {
private static int getSchemaVersion(String profileName) throws IOException { private static int getSchemaVersion(String profileName) throws IOException {
if (Files.exists(getSchemaVersionFile(profileName))) { if (Files.exists(getSchemaVersionFile(profileName))) {
return Integer.parseInt(Files.readString(getSchemaVersionFile(profileName))); try {
return Integer.parseInt(Files.readString(getSchemaVersionFile(profileName)).strip());
} catch (NumberFormatException e) {
throw new IOException("Could not parse integer schema version.", e);
}
} else { } else {
writeCurrentSchemaVersion(profileName); writeCurrentSchemaVersion(profileName);
return SCHEMA_VERSION; return SCHEMA_VERSION;

View File

@ -37,9 +37,13 @@ public class FileUtil {
public static void deleteIfPossible(Path file) { public static void deleteIfPossible(Path file) {
try { try {
if (Files.isDirectory(file)) {
deleteDirRecursive(file);
} else {
Files.deleteIfExists(file); Files.deleteIfExists(file);
}
} catch (IOException e) { } catch (IOException e) {
log.error("Failed to delete file " + file, e); log.error("Failed to delete " + file, e);
} }
} }

View File

@ -2,8 +2,9 @@ package com.andrewlalis.perfin.model;
import com.andrewlalis.perfin.PerfinApp; import com.andrewlalis.perfin.PerfinApp;
import com.andrewlalis.perfin.data.DataSource; import com.andrewlalis.perfin.data.DataSource;
import com.andrewlalis.perfin.data.DataSourceInitializationException; import com.andrewlalis.perfin.data.ProfileLoadException;
import com.andrewlalis.perfin.data.impl.JdbcDataSourceFactory; import com.andrewlalis.perfin.data.impl.JdbcDataSourceFactory;
import com.andrewlalis.perfin.data.util.FileUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -118,17 +119,24 @@ public class Profile {
} }
} }
public static void loadLast() throws IOException, DataSourceInitializationException { public static void loadLast() throws ProfileLoadException {
load(getLastProfile()); load(getLastProfile());
} }
public static void load(String name) throws IOException, DataSourceInitializationException { public static void load(String name) throws ProfileLoadException {
if (Files.notExists(getDir(name))) { if (Files.notExists(getDir(name))) {
try {
initProfileDir(name); initProfileDir(name);
} catch (IOException e) {
FileUtil.deleteIfPossible(getDir(name));
throw new ProfileLoadException("Failed to initialize new profile directory.", e);
}
} }
Properties settings = new Properties(); Properties settings = new Properties();
try (var in = Files.newInputStream(getSettingsFile(name))) { try (var in = Files.newInputStream(getSettingsFile(name))) {
settings.load(in); settings.load(in);
} catch (IOException e) {
throw new ProfileLoadException("Failed to load profile settings.", e);
} }
current = new Profile(name, settings, new JdbcDataSourceFactory().getDataSource(name)); current = new Profile(name, settings, new JdbcDataSourceFactory().getDataSource(name));
saveLastProfile(current.getName()); saveLastProfile(current.getName());

View File

@ -66,6 +66,11 @@ public class StartupSplashScreen extends Stage implements Consumer<String> {
} catch (Exception e) { } catch (Exception e) {
accept("Startup failed: " + e.getMessage()); accept("Startup failed: " + e.getMessage());
e.printStackTrace(System.err); e.printStackTrace(System.err);
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
Platform.runLater(this::close); Platform.runLater(this::close);
return; return;
} }