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.setInjector(injector);
ViewLoader loader = new ViewLoader(Navigation.Item.MAIN, false); ViewLoader loader = new ViewLoader(Navigation.Item.MAIN, false);
try {
Parent view = loader.load(); Parent view = loader.load();
Scene scene = new Scene(view, 1000, 600); Scene scene = new Scene(view, 1000, 600);
@ -122,10 +121,6 @@ public class BitsquareUI extends Application {
Profiler.initScene(primaryStage.getScene()); Profiler.initScene(primaryStage.getScene());
primaryStage.show(); primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
log.error(e.getMessage());
}
} }
private void setupCloseHandlers(Stage primaryStage, Scene scene) { 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.trade.TradeManager;
import io.bitsquare.util.ViewLoader; import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -147,7 +145,6 @@ public class MainViewCB extends ViewCB<MainPM> {
protected Initializable loadView(Navigation.Item navigationItem) { protected Initializable loadView(Navigation.Item navigationItem) {
super.loadView((navigationItem)); super.loadView((navigationItem));
final ViewLoader loader = new ViewLoader(navigationItem); final ViewLoader loader = new ViewLoader(navigationItem);
try {
final Node view = loader.load(); final Node view = loader.load();
contentContainer.getChildren().setAll(view); contentContainer.getChildren().setAll(view);
childController = loader.getController(); childController = loader.getController();
@ -156,11 +153,6 @@ public class MainViewCB extends ViewCB<MainPM> {
((ViewCB) childController).setParent(this); ((ViewCB) childController).setParent(this);
return childController; 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.gui.ViewCB;
import io.bitsquare.util.ViewLoader; import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -137,7 +135,6 @@ public class AccountViewCB extends CachedViewCB<AccountPM> {
super.loadView(navigationItem); super.loadView(navigationItem);
final ViewLoader loader = new ViewLoader(navigationItem); final ViewLoader loader = new ViewLoader(navigationItem);
try {
Node view = loader.load(); Node view = loader.load();
Tab tab = null; Tab tab = null;
switch (navigationItem) { switch (navigationItem) {
@ -164,10 +161,6 @@ public class AccountViewCB extends CachedViewCB<AccountPM> {
Initializable childController = loader.getController(); Initializable childController = loader.getController();
((ViewCB) childController).setParent(this); ((ViewCB) childController).setParent(this);
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + Navigation.Item.ACCOUNT_SETUP.getFxmlUrl());
e.printStackTrace();
}
return childController; 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.gui.main.account.arbitrator.registration.ArbitratorRegistrationViewCB;
import io.bitsquare.util.ViewLoader; import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -98,7 +96,7 @@ public class ArbitratorSettingsViewCB extends CachedViewCB {
protected Initializable loadView(Navigation.Item navigationItem) { 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 // 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); final ViewLoader loader = new ViewLoader(navigationItem, false);
try {
final Parent view = loader.load(); final Parent view = loader.load();
arbitratorRegistrationViewCB = loader.getController(); arbitratorRegistrationViewCB = loader.getController();
@ -118,10 +116,6 @@ public class ArbitratorSettingsViewCB extends CachedViewCB {
stage.show(); stage.show();
return arbitratorRegistrationViewCB; 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.settings.Settings;
import io.bitsquare.util.ViewLoader; import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
@ -141,16 +139,11 @@ public class ArbitratorBrowserViewCB extends CachedViewCB implements ArbitratorL
super.loadView(navigationItem); super.loadView(navigationItem);
final ViewLoader loader = new ViewLoader(navigationItem); final ViewLoader loader = new ViewLoader(navigationItem);
try {
Node view = loader.load(); Node view = loader.load();
((Pane) root).getChildren().set(0, view); ((Pane) root).getChildren().set(0, view);
Initializable childController = arbitratorProfileViewCB = loader.getController(); Initializable childController = arbitratorProfileViewCB = loader.getController();
((ViewCB) childController).setParent(this); ((ViewCB) childController).setParent(this);
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
e.printStackTrace();
}
return childController; return childController;
} }

View file

@ -30,8 +30,6 @@ import io.bitsquare.locale.Country;
import io.bitsquare.locale.Region; import io.bitsquare.locale.Region;
import io.bitsquare.util.ViewLoader; import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Locale; import java.util.Locale;
@ -190,7 +188,6 @@ public class RestrictionsViewCB extends CachedViewCB<RestrictionsPM> implements
protected Initializable loadView(Navigation.Item navigationItem) { protected Initializable loadView(Navigation.Item navigationItem) {
// TODO caching causes exception // TODO caching causes exception
final ViewLoader loader = new ViewLoader(navigationItem, false); final ViewLoader loader = new ViewLoader(navigationItem, false);
try {
final Node view = loader.load(); final Node view = loader.load();
//TODO Resolve type problem... //TODO Resolve type problem...
Initializable childController = loader.getController(); Initializable childController = loader.getController();
@ -216,10 +213,6 @@ public class RestrictionsViewCB extends CachedViewCB<RestrictionsPM> implements
stage.show(); stage.show();
return childController; 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.gui.util.Colors;
import io.bitsquare.util.ViewLoader; import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -149,18 +147,12 @@ public class AccountSettingsViewCB extends CachedViewCB {
@Override @Override
protected Initializable loadView(Navigation.Item navigationItem) { protected Initializable loadView(Navigation.Item navigationItem) {
final ViewLoader loader = new ViewLoader(navigationItem); final ViewLoader loader = new ViewLoader(navigationItem);
try {
final Pane view = loader.load(); final Pane view = loader.load();
content.getChildren().setAll(view); content.getChildren().setAll(view);
childController = loader.getController(); childController = loader.getController();
((ViewCB<? extends PresentationModel>) childController).setParent(this); ((ViewCB<? extends PresentationModel>) childController).setParent(this);
((ContextAware) childController).useSettingsContext(true); ((ContextAware) childController).useSettingsContext(true);
return childController; 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.gui.main.account.content.seedwords.SeedWordsViewCB;
import io.bitsquare.util.ViewLoader; import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -189,18 +187,12 @@ public class AccountSetupViewCB extends ViewCB implements MultiStepNavigation {
@Override @Override
protected Initializable loadView(Navigation.Item navigationItem) { protected Initializable loadView(Navigation.Item navigationItem) {
final ViewLoader loader = new ViewLoader(navigationItem); final ViewLoader loader = new ViewLoader(navigationItem);
try {
final Pane view = loader.load(); final Pane view = loader.load();
content.getChildren().setAll(view); content.getChildren().setAll(view);
childController = loader.getController(); childController = loader.getController();
((ViewCB<? extends PresentationModel>) childController).setParent(this); ((ViewCB<? extends PresentationModel>) childController).setParent(this);
((ContextAware) childController).useSettingsContext(false); ((ContextAware) childController).useSettingsContext(false);
return childController; 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.gui.ViewCB;
import io.bitsquare.util.ViewLoader; import io.bitsquare.util.ViewLoader;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -121,7 +119,6 @@ public class FundsViewCB extends CachedViewCB {
super.loadView(navigationItem); super.loadView(navigationItem);
final ViewLoader loader = new ViewLoader(navigationItem); final ViewLoader loader = new ViewLoader(navigationItem);
try {
Node view = loader.load(); Node view = loader.load();
Tab tab = null; Tab tab = null;
switch (navigationItem) { switch (navigationItem) {
@ -137,10 +134,6 @@ public class FundsViewCB extends CachedViewCB {
Initializable childController = loader.getController(); Initializable childController = loader.getController();
((ViewCB) childController).setParent(this); ((ViewCB) childController).setParent(this);
} catch (IOException e) {
log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl());
e.printStackTrace();
}
return childController; return childController;
} }

View file

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

View file

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

View file

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