Handle IOException within ViewLoader#load

Prior to this change, all callers of ViewLoader#load were forced to
handle the (checked) IOException declared by the #load method signature.
This resulted in a significant amount of duplicate handling logic where
nothing more than logging the error occured.

Failing to load a view represents a catastrophic error in the
application; i.e. it is not something that can be handled in any way
other than shutting the application down, fixing what is broken and
restarting the application. For this reason, any IOException raised
within ViewLoader#load is now caught, wrapped and re-thrown as an
(unchecked) RuntimeException. This will be handled by the platform's
UncaughtExceptionHandler, and a dialog will be raised to inform the user
that a fatal error has occured.

As a result all try/catch blocks around calls to ViewLoader#load have
now been removed, making for tighter, more readable, and easier to test
code.

In the future, the distinction between errors that are programmatically
recoverable and those that are catastrophic (typically developer errors)
will be used to determine whether methods in the Bitsquare API throw
checked or unchecked exceptions.
This commit is contained in:
Chris Beams 2014-11-03 16:52:11 +01:00
parent 77044d5cfe
commit e08c2bb564
No known key found for this signature in database
GPG key ID: 3D214F8F5BC5ED73
12 changed files with 168 additions and 247 deletions

View file

@ -104,7 +104,6 @@ public class BitsquareUI extends Application {
ViewLoader.setInjector(injector);
ViewLoader loader = new ViewLoader(Navigation.Item.MAIN, false);
try {
Parent view = loader.load();
Scene scene = new Scene(view, 1000, 600);
@ -122,10 +121,6 @@ public class BitsquareUI extends Application {
Profiler.initScene(primaryStage.getScene());
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
private void setupCloseHandlers(Stage primaryStage, Scene scene) {

View file

@ -30,8 +30,6 @@ import io.bitsquare.settings.Settings;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
@ -147,7 +145,6 @@ public class MainViewCB extends ViewCB<MainPM> {
protected Initializable loadView(Navigation.Item navigationItem) {
super.loadView((navigationItem));
final ViewLoader loader = new ViewLoader(navigationItem);
try {
final Node view = loader.load();
contentContainer.getChildren().setAll(view);
childController = loader.getController();
@ -156,11 +153,6 @@ public class MainViewCB extends ViewCB<MainPM> {
((ViewCB) childController).setParent(this);
return childController;
} catch (IOException e) {
e.printStackTrace();
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
}
return null;
}

View file

@ -22,8 +22,6 @@ import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.ViewCB;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
@ -137,7 +135,6 @@ public class AccountViewCB extends CachedViewCB<AccountPM> {
super.loadView(navigationItem);
final ViewLoader loader = new ViewLoader(navigationItem);
try {
Node view = loader.load();
Tab tab = null;
switch (navigationItem) {
@ -164,10 +161,6 @@ public class AccountViewCB extends CachedViewCB<AccountPM> {
Initializable childController = loader.getController();
((ViewCB) childController).setParent(this);
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + Navigation.Item.ACCOUNT_SETUP.getFxmlUrl());
e.printStackTrace();
}
return childController;
}

View file

@ -23,8 +23,6 @@ import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.main.account.arbitrator.registration.ArbitratorRegistrationViewCB;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
@ -98,7 +96,7 @@ public class ArbitratorSettingsViewCB extends CachedViewCB {
protected Initializable loadView(Navigation.Item navigationItem) {
// don't use caching here, cause exc. -> need to investigate and is rarely called so no caching is better
final ViewLoader loader = new ViewLoader(navigationItem, false);
try {
final Parent view = loader.load();
arbitratorRegistrationViewCB = loader.getController();
@ -118,10 +116,6 @@ public class ArbitratorSettingsViewCB extends CachedViewCB {
stage.show();
return arbitratorRegistrationViewCB;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

View file

@ -29,8 +29,6 @@ import io.bitsquare.persistence.Persistence;
import io.bitsquare.settings.Settings;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
@ -141,16 +139,11 @@ public class ArbitratorBrowserViewCB extends CachedViewCB implements ArbitratorL
super.loadView(navigationItem);
final ViewLoader loader = new ViewLoader(navigationItem);
try {
Node view = loader.load();
((Pane) root).getChildren().set(0, view);
Initializable childController = arbitratorProfileViewCB = loader.getController();
((ViewCB) childController).setParent(this);
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
e.printStackTrace();
}
return childController;
}

View file

@ -30,8 +30,6 @@ import io.bitsquare.locale.Country;
import io.bitsquare.locale.Region;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.Locale;
@ -190,7 +188,6 @@ public class RestrictionsViewCB extends CachedViewCB<RestrictionsPM> implements
protected Initializable loadView(Navigation.Item navigationItem) {
// TODO caching causes exception
final ViewLoader loader = new ViewLoader(navigationItem, false);
try {
final Node view = loader.load();
//TODO Resolve type problem...
Initializable childController = loader.getController();
@ -216,10 +213,6 @@ public class RestrictionsViewCB extends CachedViewCB<RestrictionsPM> implements
stage.show();
return childController;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

View file

@ -25,8 +25,6 @@ import io.bitsquare.gui.main.account.content.ContextAware;
import io.bitsquare.gui.util.Colors;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
@ -149,18 +147,12 @@ public class AccountSettingsViewCB extends CachedViewCB {
@Override
protected Initializable loadView(Navigation.Item navigationItem) {
final ViewLoader loader = new ViewLoader(navigationItem);
try {
final Pane view = loader.load();
content.getChildren().setAll(view);
childController = loader.getController();
((ViewCB<? extends PresentationModel>) childController).setParent(this);
((ContextAware) childController).useSettingsContext(true);
return childController;
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
e.printStackTrace();
}
return null;
}

View file

@ -29,8 +29,6 @@ import io.bitsquare.gui.main.account.content.restrictions.RestrictionsViewCB;
import io.bitsquare.gui.main.account.content.seedwords.SeedWordsViewCB;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
@ -189,18 +187,12 @@ public class AccountSetupViewCB extends ViewCB implements MultiStepNavigation {
@Override
protected Initializable loadView(Navigation.Item navigationItem) {
final ViewLoader loader = new ViewLoader(navigationItem);
try {
final Pane view = loader.load();
content.getChildren().setAll(view);
childController = loader.getController();
((ViewCB<? extends PresentationModel>) childController).setParent(this);
((ContextAware) childController).useSettingsContext(false);
return childController;
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
e.printStackTrace();
}
return null;
}
}

View file

@ -22,8 +22,6 @@ import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.ViewCB;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
@ -121,7 +119,6 @@ public class FundsViewCB extends CachedViewCB {
super.loadView(navigationItem);
final ViewLoader loader = new ViewLoader(navigationItem);
try {
Node view = loader.load();
Tab tab = null;
switch (navigationItem) {
@ -137,10 +134,6 @@ public class FundsViewCB extends CachedViewCB {
Initializable childController = loader.getController();
((ViewCB) childController).setParent(this);
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
e.printStackTrace();
}
return childController;
}

View file

@ -23,8 +23,6 @@ import io.bitsquare.gui.ViewCB;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
@ -127,7 +125,6 @@ public class PortfolioViewCB extends CachedViewCB {
super.loadView(navigationItem);
final ViewLoader loader = new ViewLoader(navigationItem);
try {
Parent view = loader.load();
Tab tab = null;
switch (navigationItem) {
@ -146,10 +143,6 @@ public class PortfolioViewCB extends CachedViewCB {
Initializable childController = loader.getController();
((ViewCB) childController).setParent(this);
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
e.printStackTrace();
}
return childController;
}
}

View file

@ -30,8 +30,6 @@ import io.bitsquare.util.ViewLoader;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat;
import java.io.IOException;
import java.net.URL;
import java.util.List;
@ -169,7 +167,6 @@ public class TradeViewCB extends CachedViewCB implements TradeNavigator {
if (navigationItem == Navigation.Item.OFFER_BOOK && offerBookViewCB == null) {
// Offerbook must not be cached by ViewLoader as we use 2 instances for sell and buy screens.
ViewLoader offerBookLoader = new ViewLoader(navigationItem, false);
try {
final Parent view = offerBookLoader.load();
final Tab tab = new Tab(direction == Direction.BUY ? "Buy Bitcoin" : "Sell Bitcoin");
tab.setClosable(false);
@ -182,15 +179,11 @@ public class TradeViewCB extends CachedViewCB implements TradeNavigator {
// offerBookViewCB.setNavigationListener(n -> loadView(n));
return offerBookViewCB;
} catch (IOException e) {
log.error(e.getMessage());
}
}
else if (navigationItem == Navigation.Item.CREATE_OFFER && createOfferViewCB == null) {
// CreateOffer and TakeOffer must not be cached by ViewLoader as we cannot use a view multiple times
// in different graphs
final ViewLoader loader = new ViewLoader(navigationItem, false);
try {
createOfferView = loader.load();
createOfferViewCB = loader.getController();
createOfferViewCB.setParent(this);
@ -201,16 +194,12 @@ public class TradeViewCB extends CachedViewCB implements TradeNavigator {
tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tab);
return createOfferViewCB;
} catch (IOException e) {
log.error(e.getMessage());
}
}
else if (navigationItem == Navigation.Item.TAKE_OFFER && takeOfferViewCB == null &&
offer != null) {
// CreateOffer and TakeOffer must not be cached by ViewLoader as we cannot use a view multiple times
// in different graphs
ViewLoader loader = new ViewLoader(Navigation.Item.TAKE_OFFER, false);
try {
takeOfferView = loader.load();
takeOfferViewCB = loader.getController();
takeOfferViewCB.setParent(this);
@ -221,9 +210,6 @@ public class TradeViewCB extends CachedViewCB implements TradeNavigator {
tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tab);
return takeOfferViewCB;
} catch (IOException e) {
log.error(e.getMessage());
}
}
return null;
}

View file

@ -22,6 +22,8 @@ import io.bitsquare.locale.BSResources;
import com.google.inject.Injector;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
@ -69,18 +71,21 @@ public class ViewLoader {
}
@SuppressWarnings("unchecked")
public <T> T load() throws java.io.IOException {
public <T> T load() {
if (isCached) {
item = cachedGUIItems.get(url);
log.debug("loaded from cache " + url);
return (T) cachedGUIItems.get(url).view;
}
else {
log.debug("load from disc " + url);
try {
T result = loader.load();
item = new Item(result, loader.getController());
cachedGUIItems.put(url, item);
return result;
} catch (IOException e) {
throw new RuntimeException("Failed to load view at " + url, e);
}
}