Overhaul property management and main class infrastructure

Use of the Spring Environment
-----------------------------

This change replaces the use of the argparse4j library and basic
Properties objects with the Spring Framework's Environment abstraction.
The Environment allows for managing any number of 'property sources' in
a hierarchical fashion, such that a call to
`environment.getProperty("someKey")` iterates through an ordered set of
property sources, returning the first value associated with the given
key.

BitsquareEnvironment, introduced in this commit, eliminates the
functionality previously present in ConfigLoader, modeling the
bitsquare.conf and bitsquare.properties files as Spring Resource
objects, and in turn creating ResourcePropertySources out of them. These
custom property sources are combined with standard property sources
based on system environment variables and Java system properties as well
as a property source based on the command-line arguments passed to a
Bitsquare application to form a unified, one-stop configuration
hierarchy.

For example, let's say a Bitsquare user wishes to customize the port
that his Bitsquare application listens on. The simplest approach
(assuming the user is comfortable with the command line), would be the
following:

    java -jar bitsquare.jar --port=1234

where '1234' is the custom port of choice. This is convenient enough for
one-off experimentation, but if the user wishes to make this a permanent
arrangement, he may want to add a `port=1234` entry to his
{bitsquare_app_dir}/bitsquare.conf file.

Alternatively, the user may wish to specify the port value as an
environment variable, e.g.:

    PORT=1234 java -jar bitsquare.jar

or with a JVM system property, e.g.:

    java -jar -DPORT=1234 bitsquare.jar

With BitsquareEnvironment, and its customized set of PropertySources in
place, the value of the port property may be specified in any of the
ways described above, and it is all handled in a unified way.

Restructuring of *Main classes
------------------------------

This commit also introduces significant changes to the structure of
executable Bitsquare applications. For example, prior to this change,
the io.bitsquare.app.gui.Main class was responsible for being both a
JavaFX Application and a standard Java main class.

Now, however, these concerns have been renamed and separated.
BitsquareApp is the JavaFX Application, and BitsquareAppMain is the Java
main class. Likewise, BootstrapNode has been broken out into
BootstrapNode and BootstrapNodeMain.

A common base class for the *Main classes has been extracted, named
BitsquareExecutable, which creates a template for option parsing,
environment creation, and ultimately application execution that applies
both to the BootstrapNode and BitsquareApp cases.

Improved help text
------------------

With the removal of argparse4j and the introduction of JOpt for argument
parsing, the application's help text has been improved. Use --help to
display this text, where you'll see information about default values,
etc. To do this easily from the Gradle build, run any of the following
commands:

    # Display help text
    ./gradlew run -Pargs="--help"

    # Qualify the application name as "Bitsquare-Alice"
    ./gradlew run -Pargs="--appName=Alice"

    # Customize the port
    ./gradlew run -Pargs="--port=7377"

Renaming of FatalException
--------------------------

Finally, the exception formerly known as io.bitsquare.gui.FatalException
has been moved up a package and generalized to
io.bitsquare.BitsquareException, as it is now used more widely.
This commit is contained in:
Chris Beams 2014-11-10 15:48:27 +01:00
parent 882b7c2842
commit acf44128b2
No known key found for this signature in database
GPG key ID: 3D214F8F5BC5ED73
23 changed files with 380 additions and 305 deletions

View file

@ -17,7 +17,7 @@ sourceCompatibility = 1.8
sourceSets.main.resources.srcDirs += 'src/main/java'
mainClassName = "io.bitsquare.app.gui.Main"
mainClassName = "io.bitsquare.app.gui.BitsquareAppMain"
run {
if (project.hasProperty('args')) {
@ -33,6 +33,8 @@ repositories {
dependencies {
compile 'org.bitcoinj:bitcoinj-core:0.12'
compile 'net.tomp2p:tomp2p-all:5.0-Alpha.32cd9f9-SNAPSHOT'
compile 'org.springframework:spring-core:4.1.1.RELEASE'
compile 'net.sf.jopt-simple:jopt-simple:4.8'
compile 'org.slf4j:slf4j-api:1.7.7'
compile 'ch.qos.logback:logback-core:1.1.2'
compile 'ch.qos.logback:logback-classic:1.1.2'
@ -45,7 +47,6 @@ dependencies {
compile 'com.google.code.findbugs:jsr305:2.0.3'
compile 'net.jcip:jcip-annotations:1.0'
compile 'org.jetbrains:annotations:13.0'
compile 'net.sourceforge.argparse4j:argparse4j:0.4.4'
compile 'eu.hansolo.enzo:Enzo:0.1.5'
testCompile 'junit:junit:4.11'
}

View file

@ -15,16 +15,20 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui;
package io.bitsquare;
@SuppressWarnings("serializable")
public class FatalException extends RuntimeException {
public class BitsquareException extends RuntimeException {
public FatalException(String format, Object... args) {
public BitsquareException(Throwable cause) {
super(cause);
}
public BitsquareException(String format, Object... args) {
super(String.format(format, args));
}
public FatalException(Throwable cause, String format, Object... args) {
public BitsquareException(Throwable cause, String format, Object... args) {
super(String.format(format, args), cause);
}
}

View file

@ -22,17 +22,18 @@ import com.google.common.collect.Sets;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import java.util.Properties;
import java.util.Set;
import org.springframework.core.env.Environment;
public abstract class BitsquareModule extends AbstractModule {
protected final Properties properties;
protected final Environment env;
private final Set<BitsquareModule> modules = Sets.newHashSet();
protected BitsquareModule(Properties properties) {
this.properties = properties;
protected BitsquareModule(Environment env) {
this.env = env;
}
protected void install(BitsquareModule module) {

View file

@ -1,75 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app;
import io.bitsquare.btc.BitcoinModule;
import io.bitsquare.network.Node;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.Namespace;
import static io.bitsquare.app.AppModule.APP_NAME_KEY;
import static io.bitsquare.msg.tomp2p.TomP2PMessageModule.*;
public class ArgumentParser {
private final net.sourceforge.argparse4j.inf.ArgumentParser parser;
public ArgumentParser() {
parser = ArgumentParsers.newArgumentParser("Bitsquare")
.defaultHelp(true)
.description("Bitsquare - The decentralized bitcoin exchange");
// Args for local node config
parser.addArgument("--" + Node.NAME_KEY)
.help("Local node name");
parser.addArgument("--" + Node.PORT_KEY)
.help("Local node port");
// Args for bootstrap node config
parser.addArgument("--" + BOOTSTRAP_NODE_NAME_KEY)
.help("Bootstrap node name");
parser.addArgument("--" + BOOTSTRAP_NODE_IP_KEY)
.help("Bootstrap node IP address");
parser.addArgument("--" + BOOTSTRAP_NODE_PORT_KEY)
.help("Bootstrap node port");
// A custom network interface (needed at the moment for windows, but might be useful also later)
parser.addArgument("--" + NETWORK_INTERFACE_KEY)
.help("Network interface");
parser.addArgument("--" + BitcoinModule.BITCOIN_NETWORK_KEY)
.setDefault(BitcoinModule.DEFAULT_BITCOIN_NETWORK.toString())
.help("Bitcoin network to use");
// Args for app config
parser.addArgument("-n", "--" + APP_NAME_KEY)
.help("Name to append to default application name");
}
public Namespace parseArgs(String... args) {
try {
return parser.parseArgs(args);
} catch (ArgumentParserException e) {
parser.handleError(e);
System.exit(1);
return null;
}
}
}

View file

@ -0,0 +1,98 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app;
import io.bitsquare.BitsquareException;
import com.google.common.base.Preconditions;
import java.io.IOException;
import java.util.Properties;
import joptsimple.OptionSet;
import lighthouse.files.AppDirectory;
import org.springframework.core.env.JOptCommandLinePropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePropertySource;
public class BitsquareEnvironment extends StandardEnvironment {
public static final String APP_NAME_KEY = "appName";
public static final String DEFAULT_APP_NAME = "Bitsquare";
private static final String BITSQUARE_APP_PROPERTY_SOURCE_NAME = "bitsquareAppProperties";
private static final String BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME = "bitsquareClasspathProperties";
private static final String BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME = "bitsquareFilesystemProperties";
private static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties";
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
public BitsquareEnvironment(OptionSet options) {
Preconditions.checkArgument(options != null, "Options must not be null");
PropertySource commandLineProperties =
new JOptCommandLinePropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME, options);
String appName = commandLineProperties.containsProperty(APP_NAME_KEY) ?
DEFAULT_APP_NAME + "-" + commandLineProperties.getProperty(APP_NAME_KEY) :
DEFAULT_APP_NAME;
MutablePropertySources propertySources = this.getPropertySources();
propertySources.addBefore(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, appProperties(appName));
propertySources.addBefore(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, classpathProperties());
propertySources.addBefore(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, filesystemProperties(appName));
propertySources.addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, commandLineProperties);
}
private PropertySource<?> appProperties(String appName) {
return new PropertiesPropertySource(BITSQUARE_APP_PROPERTY_SOURCE_NAME, new Properties() {{
setProperty(APP_NAME_KEY, appName);
}});
}
private PropertySource<?> classpathProperties() {
try {
Resource resource = resourceLoader.getResource("classpath:bitsquare.properties");
return new ResourcePropertySource(BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME, resource);
} catch (IOException ex) {
throw new BitsquareException(ex);
}
}
private PropertySource<?> filesystemProperties(String appName) {
String location = String.format("file:%s/bitsquare.conf", AppDirectory.dir(appName));
Resource resource = resourceLoader.getResource(location);
if (!resource.exists()) {
return new PropertySource.StubPropertySource(BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME);
}
try {
return new ResourcePropertySource(BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME, resource);
} catch (IOException ex) {
throw new BitsquareException(ex);
}
}
}

View file

@ -0,0 +1,57 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app;
import joptsimple.OptionException;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
public abstract class BitsquareExecutable {
public static final int EXIT_SUCCESS = 0;
public static final int EXIT_FAILURE = 1;
public static final String HELP_KEY = "help";
public void execute(String[] args) throws Exception {
OptionParser parser = new OptionParser();
parser.accepts(HELP_KEY, "This help text").forHelp();
this.customizeOptionParsing(parser);
OptionSet options;
try {
options = parser.parse(args);
if (options.has(HELP_KEY)) {
parser.printHelpOn(System.out);
System.exit(EXIT_SUCCESS);
return;
}
} catch (OptionException ex) {
System.out.println("error: " + ex.getMessage());
System.out.println();
parser.printHelpOn(System.out);
System.exit(EXIT_FAILURE);
return;
}
this.doExecute(options);
}
protected abstract void customizeOptionParsing(OptionParser parser);
protected abstract void doExecute(OptionSet options);
}

View file

@ -17,7 +17,6 @@
package io.bitsquare.app.cli;
import io.bitsquare.app.ArgumentParser;
import io.bitsquare.network.Node;
import net.tomp2p.dht.PeerBuilderDHT;
@ -33,7 +32,7 @@ import net.tomp2p.rpc.ObjectDataReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sourceforge.argparse4j.inf.Namespace;
import org.springframework.core.env.Environment;
public class BootstrapNode {
private static final Logger log = LoggerFactory.getLogger(BootstrapNode.class);
@ -41,16 +40,15 @@ public class BootstrapNode {
private static Peer peer = null;
private static boolean running = true;
public static void main(String[] args) throws Exception {
ArgumentParser parser = new ArgumentParser();
Namespace namespace = parser.parseArgs(args);
private final Environment env;
String name = namespace.getString(Node.NAME_KEY);
if (name == null)
throw new IllegalArgumentException(String.format("--%s option is required", Node.NAME_KEY));
public BootstrapNode(Environment env) {
this.env = env;
}
String portValue = namespace.getString(Node.PORT_KEY);
int port = portValue != null ? Integer.valueOf(portValue) : Node.DEFAULT_PORT;
public void start() {
String name = env.getRequiredProperty(Node.NAME_KEY);
int port = env.getProperty(Node.PORT_KEY, Integer.class, Node.DEFAULT_PORT);
try {
Number160 peerId = Number160.createHash(name);
@ -90,12 +88,4 @@ public class BootstrapNode {
peer.shutdown().awaitUninterruptibly();
}
}
public static void stop() {
running = false;
if (peer != null) {
peer.shutdown().awaitUninterruptibly();
}
peer = null;
}
}

View file

@ -0,0 +1,42 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app.cli;
import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.app.BitsquareExecutable;
import io.bitsquare.network.Node;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
public class BootstrapNodeMain extends BitsquareExecutable {
public static void main(String[] args) throws Exception {
new BootstrapNodeMain().execute(args);
}
protected void customizeOptionParsing(OptionParser parser) {
parser.accepts(Node.NAME_KEY, "Name of this node").withRequiredArg().isRequired();
parser.accepts(Node.PORT_KEY, "Port to listen on").withRequiredArg()
.defaultsTo(String.valueOf(Node.DEFAULT_PORT));
}
protected void doExecute(OptionSet options) {
new BootstrapNode(new BitsquareEnvironment(options)).start();
}
}

View file

@ -17,7 +17,7 @@
package io.bitsquare.app.gui;
import io.bitsquare.app.ArgumentParser;
import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.SystemTray;
import io.bitsquare.gui.ViewLoader;
@ -26,8 +26,8 @@ import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.persistence.Persistence;
import io.bitsquare.settings.Settings;
import io.bitsquare.user.User;
import io.bitsquare.util.ConfigLoader;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.inject.Guice;
@ -35,8 +35,6 @@ import com.google.inject.Injector;
import java.io.IOException;
import java.util.Properties;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.image.*;
@ -47,59 +45,28 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lighthouse.files.AppDirectory;
import net.sourceforge.argparse4j.inf.Namespace;
import org.springframework.core.env.Environment;
import static io.bitsquare.app.AppModule.APP_NAME_KEY;
import static io.bitsquare.btc.BitcoinModule.BITCOIN_NETWORK_KEY;
import static io.bitsquare.msg.tomp2p.TomP2PMessageModule.*;
import static io.bitsquare.network.Node.*;
public class BitsquareApp extends Application {
private static final Logger log = LoggerFactory.getLogger(BitsquareApp.class);
public class Main extends Application {
private static final Logger log = LoggerFactory.getLogger(Main.class);
private static String appName = "Bitsquare";
private static Properties properties;
private static Environment env;
private MainModule mainModule;
private BitsquareAppModule bitsquareAppModule;
private Injector injector;
public static void main(String[] args) {
Namespace argumentsNamespace = new ArgumentParser().parseArgs(args);
if (argumentsNamespace.getString(APP_NAME_KEY) != null)
appName = appName + "-" + argumentsNamespace.getString(APP_NAME_KEY);
properties = ConfigLoader.loadConfig(appName);
properties.setProperty(APP_NAME_KEY, appName);
if (argumentsNamespace.getString(NAME_KEY) != null)
properties.setProperty(NAME_KEY, argumentsNamespace.getString(NAME_KEY));
if (argumentsNamespace.getString(PORT_KEY) != null)
properties.setProperty(PORT_KEY, argumentsNamespace.getString(PORT_KEY));
if (argumentsNamespace.getString(BOOTSTRAP_NODE_NAME_KEY) != null)
properties.setProperty(BOOTSTRAP_NODE_NAME_KEY, argumentsNamespace.getString(BOOTSTRAP_NODE_NAME_KEY));
if (argumentsNamespace.getString(BOOTSTRAP_NODE_IP_KEY) != null)
properties.setProperty(BOOTSTRAP_NODE_IP_KEY, argumentsNamespace.getString(BOOTSTRAP_NODE_IP_KEY));
if (argumentsNamespace.getString(BOOTSTRAP_NODE_PORT_KEY) != null)
properties.setProperty(BOOTSTRAP_NODE_PORT_KEY, argumentsNamespace.getString(BOOTSTRAP_NODE_PORT_KEY));
if (argumentsNamespace.getString(NETWORK_INTERFACE_KEY) != null)
properties.setProperty(NETWORK_INTERFACE_KEY, argumentsNamespace.getString(NETWORK_INTERFACE_KEY));
if (argumentsNamespace.getString(BITCOIN_NETWORK_KEY) != null)
properties.setProperty(BITCOIN_NETWORK_KEY, argumentsNamespace.getString(BITCOIN_NETWORK_KEY));
Application.launch(Main.class, args);
public static void setEnvironment(Environment env) {
BitsquareApp.env = env;
}
@Override
public void start(Stage primaryStage) {
mainModule = new MainModule(properties, primaryStage);
injector = Guice.createInjector(mainModule);
public void start(Stage primaryStage) throws IOException {
Preconditions.checkArgument(env != null, "Environment must not be null");
String appName = env.getRequiredProperty(BitsquareEnvironment.APP_NAME_KEY);
bitsquareAppModule = new BitsquareAppModule(env, primaryStage);
injector = Guice.createInjector(bitsquareAppModule);
// route uncaught exceptions to a user-facing dialog
@ -173,7 +140,7 @@ public class Main extends Application {
@Override
public void stop() {
mainModule.close(injector);
bitsquareAppModule.close(injector);
System.exit(0);
}
}

View file

@ -0,0 +1,57 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app.gui;
import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.app.BitsquareExecutable;
import io.bitsquare.btc.BitcoinModule;
import io.bitsquare.network.BootstrapNodes;
import io.bitsquare.network.Node;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import static io.bitsquare.app.BitsquareEnvironment.APP_NAME_KEY;
import static io.bitsquare.btc.BitcoinModule.BITCOIN_NETWORK_KEY;
import static io.bitsquare.msg.tomp2p.TomP2PMessageModule.*;
import static io.bitsquare.network.Node.*;
public class BitsquareAppMain extends BitsquareExecutable {
public static void main(String[] args) throws Exception {
new BitsquareAppMain().execute(args);
}
@Override
protected void customizeOptionParsing(OptionParser parser) {
parser.accepts(APP_NAME_KEY, "Qualified application name").withRequiredArg();
parser.accepts(NAME_KEY, "Name of this node").withRequiredArg();
parser.accepts(PORT_KEY, "Port to listen on").withRequiredArg().defaultsTo(String.valueOf(Node.DEFAULT_PORT));
parser.accepts(BITCOIN_NETWORK_KEY).withRequiredArg().defaultsTo(BitcoinModule.DEFAULT_BITCOIN_NETWORK);
parser.accepts(BOOTSTRAP_NODE_NAME_KEY).withRequiredArg().defaultsTo(BootstrapNodes.DEFAULT.getName());
parser.accepts(BOOTSTRAP_NODE_IP_KEY).withRequiredArg().defaultsTo(BootstrapNodes.DEFAULT.getIp());
parser.accepts(BOOTSTRAP_NODE_PORT_KEY).withRequiredArg().defaultsTo(BootstrapNodes.DEFAULT.getPortAsString());
parser.accepts(NETWORK_INTERFACE_KEY, "Network interface").withRequiredArg();
}
@Override
protected void doExecute(OptionSet options) {
BitsquareApp.setEnvironment(new BitsquareEnvironment(options));
javafx.application.Application.launch(BitsquareApp.class);
}
}

View file

@ -15,11 +15,13 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app;
package io.bitsquare.app.gui;
import io.bitsquare.BitsquareModule;
import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.btc.BitcoinModule;
import io.bitsquare.crypto.CryptoModule;
import io.bitsquare.gui.GuiModule;
import io.bitsquare.msg.MessageModule;
import io.bitsquare.msg.tomp2p.TomP2PMessageModule;
import io.bitsquare.offer.OfferModule;
@ -29,21 +31,20 @@ import io.bitsquare.settings.Settings;
import io.bitsquare.trade.TradeModule;
import io.bitsquare.user.User;
import com.google.common.base.Preconditions;
import com.google.inject.Injector;
import com.google.inject.name.Names;
import java.util.Properties;
import javafx.stage.Stage;
/**
* Configures all non-UI modules necessary to run a Bitsquare application.
*/
public class AppModule extends BitsquareModule {
public static final String APP_NAME_KEY = "appName";
import org.springframework.core.env.Environment;
public AppModule(Properties properties) {
super(properties);
class BitsquareAppModule extends BitsquareModule {
private final Stage primaryStage;
public BitsquareAppModule(Environment env, Stage primaryStage) {
super(env);
this.primaryStage = primaryStage;
}
@Override
@ -57,35 +58,38 @@ public class AppModule extends BitsquareModule {
install(cryptoModule());
install(tradeModule());
install(offerModule());
install(guiModule());
String appName = properties.getProperty(APP_NAME_KEY);
Preconditions.checkArgument(appName != null, "App name must be non-null");
String appName = env.getRequiredProperty(BitsquareEnvironment.APP_NAME_KEY);
bindConstant().annotatedWith(Names.named("appName")).to(appName);
}
protected MessageModule messageModule() {
return new TomP2PMessageModule(properties);
return new TomP2PMessageModule(env);
}
protected BitcoinModule bitcoinModule() {
return new BitcoinModule(properties);
return new BitcoinModule(env);
}
protected CryptoModule cryptoModule() {
return new CryptoModule(properties);
return new CryptoModule(env);
}
protected TradeModule tradeModule() {
return new TradeModule(properties);
return new TradeModule(env);
}
protected OfferModule offerModule() {
return new TomP2POfferModule(properties);
return new TomP2POfferModule(env);
}
protected GuiModule guiModule() {
return new GuiModule(env, primaryStage);
}
@Override
protected void doClose(Injector injector) {
}
}

View file

@ -26,15 +26,15 @@ import org.bitcoinj.params.TestNet3Params;
import com.google.inject.Injector;
import java.util.Properties;
import org.springframework.core.env.Environment;
public class BitcoinModule extends BitsquareModule {
public static final String BITCOIN_NETWORK_KEY = "bitcoin.network";
public static final String DEFAULT_BITCOIN_NETWORK = BitcoinNetwork.TESTNET.toString();
public BitcoinModule(Properties properties) {
super(properties);
public BitcoinModule(Environment env) {
super(env);
}
@Override
@ -52,7 +52,7 @@ public class BitcoinModule extends BitsquareModule {
private NetworkParameters network() {
BitcoinNetwork network = BitcoinNetwork.valueOf(
properties.getProperty(BITCOIN_NETWORK_KEY, DEFAULT_BITCOIN_NETWORK).toUpperCase());
env.getProperty(BITCOIN_NETWORK_KEY, DEFAULT_BITCOIN_NETWORK).toUpperCase());
switch (network) {
case MAINNET:

View file

@ -19,12 +19,12 @@ package io.bitsquare.crypto;
import io.bitsquare.BitsquareModule;
import java.util.Properties;
import org.springframework.core.env.Environment;
public class CryptoModule extends BitsquareModule {
public CryptoModule(Properties properties) {
super(properties);
public CryptoModule(Environment env) {
super(env);
}
@Override

View file

@ -28,16 +28,16 @@ import io.bitsquare.gui.util.validation.FiatValidator;
import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.gui.util.validation.PasswordValidator;
import java.util.Properties;
import javafx.stage.Stage;
import org.springframework.core.env.Environment;
public class GuiModule extends BitsquareModule {
private final Stage primaryStage;
public GuiModule(Properties properties, Stage primaryStage) {
super(properties);
public GuiModule(Environment env, Stage primaryStage) {
super(env);
this.primaryStage = primaryStage;
}

View file

@ -17,6 +17,7 @@
package io.bitsquare.gui;
import io.bitsquare.BitsquareException;
import io.bitsquare.locale.BSResources;
import com.google.inject.Injector;
@ -56,7 +57,7 @@ public class ViewLoader {
public ViewLoader(Navigation.FxmlResource navItem, boolean useCaching) {
this.url = ViewLoader.class.getResource(navItem.getFxmlUrl());
if (this.url == null) {
throw new FatalException("'%s' could not be loaded as a resource", navItem.getFxmlUrl());
throw new BitsquareException("'%s' could not be loaded as a resource", navItem.getFxmlUrl());
}
isCached = useCaching && cachedGUIItems.containsKey(url);
@ -87,7 +88,7 @@ public class ViewLoader {
cachedGUIItems.put(url, item);
return result;
} catch (IOException e) {
throw new FatalException(e, "Failed to load view at %s", url);
throw new BitsquareException(e, "Failed to load view at %s", url);
}
}

View file

@ -21,12 +21,12 @@ import io.bitsquare.BitsquareModule;
import com.google.inject.Injector;
import java.util.Properties;
import org.springframework.core.env.Environment;
public abstract class MessageModule extends BitsquareModule {
protected MessageModule(Properties properties) {
super(properties);
protected MessageModule(Environment env) {
super(env);
}
@Override

View file

@ -24,7 +24,7 @@ import io.bitsquare.network.Node;
import com.google.inject.name.Names;
import java.util.Properties;
import org.springframework.core.env.Environment;
import static io.bitsquare.msg.tomp2p.BootstrappedPeerFactory.*;
@ -35,25 +35,25 @@ public class TomP2PMessageModule extends MessageModule {
public static final String BOOTSTRAP_NODE_PORT_KEY = "bootstrap.node.port";
public static final String NETWORK_INTERFACE_KEY = BootstrappedPeerFactory.NETWORK_INTERFACE_KEY;
public TomP2PMessageModule(Properties properties) {
super(properties);
public TomP2PMessageModule(Environment env) {
super(env);
}
@Override
protected void doConfigure() {
bind(int.class).annotatedWith(Names.named(Node.PORT_KEY)).toInstance(
Integer.valueOf(properties.getProperty(Node.PORT_KEY, String.valueOf(Node.DEFAULT_PORT))));
env.getProperty(Node.PORT_KEY, Integer.class, Node.DEFAULT_PORT));
bind(TomP2PNode.class).asEagerSingleton();
bind(Node.class).annotatedWith(Names.named(BOOTSTRAP_NODE_KEY)).toInstance(
Node.at(
properties.getProperty(BOOTSTRAP_NODE_NAME_KEY, BootstrapNodes.DEFAULT.getName()),
properties.getProperty(BOOTSTRAP_NODE_IP_KEY, BootstrapNodes.DEFAULT.getIp()),
properties.getProperty(BOOTSTRAP_NODE_PORT_KEY, BootstrapNodes.DEFAULT.getPortAsString())
env.getProperty(BOOTSTRAP_NODE_NAME_KEY, BootstrapNodes.DEFAULT.getName()),
env.getProperty(BOOTSTRAP_NODE_IP_KEY, BootstrapNodes.DEFAULT.getIp()),
env.getProperty(BOOTSTRAP_NODE_PORT_KEY, BootstrapNodes.DEFAULT.getPortAsString())
)
);
bindConstant().annotatedWith(Names.named(NETWORK_INTERFACE_KEY)).to(
properties.getProperty(NETWORK_INTERFACE_KEY, NETWORK_INTERFACE_UNSPECIFIED));
env.getProperty(NETWORK_INTERFACE_KEY, NETWORK_INTERFACE_UNSPECIFIED));
bind(BootstrappedPeerFactory.class).asEagerSingleton();
}

View file

@ -19,12 +19,12 @@ package io.bitsquare.offer;
import io.bitsquare.BitsquareModule;
import java.util.Properties;
import org.springframework.core.env.Environment;
public abstract class OfferModule extends BitsquareModule {
protected OfferModule(Properties properties) {
super(properties);
protected OfferModule(Environment env) {
super(env);
}
@Override

View file

@ -20,12 +20,12 @@ package io.bitsquare.offer.tomp2p;
import io.bitsquare.offer.OfferModule;
import io.bitsquare.offer.OfferRepository;
import java.util.Properties;
import org.springframework.core.env.Environment;
public class TomP2POfferModule extends OfferModule {
public TomP2POfferModule(Properties properties) {
super(properties);
public TomP2POfferModule(Environment env) {
super(env);
}
@Override

View file

@ -19,12 +19,12 @@ package io.bitsquare.trade;
import io.bitsquare.BitsquareModule;
import java.util.Properties;
import org.springframework.core.env.Environment;
public class TradeModule extends BitsquareModule {
public TradeModule(Properties properties) {
super(properties);
public TradeModule(Environment env) {
super(env);
}
@Override

View file

@ -1,77 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lighthouse.files.AppDirectory;
public class ConfigLoader {
private static final Logger log = LoggerFactory.getLogger(ConfigLoader.class);
private static String configFilePath;
public static Properties loadConfig(String appName) {
configFilePath = AppDirectory.dir(appName) + "/bitsquare.conf";
InputStream inputStream = null;
// load default properties from class path
Properties defaultProperties = new Properties();
try {
InputStream is = ConfigLoader.class.getResourceAsStream("/bitsquare.properties");
defaultProperties.load(is);
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
// load properties file from config file path
Properties properties = new Properties(defaultProperties);
if (new File(configFilePath).exists()) {
try {
inputStream = new FileInputStream(configFilePath);
properties.load(inputStream);
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
return properties;
}
}

View file

@ -15,27 +15,27 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app.gui;
package io.bitsquare;
import io.bitsquare.BitsquareModule;
import io.bitsquare.app.AppModule;
import io.bitsquare.gui.GuiModule;
import io.bitsquare.app.BitsquareEnvironment;
import java.util.Properties;
import org.junit.Test;
import javafx.stage.Stage;
import joptsimple.OptionParser;
class MainModule extends BitsquareModule {
private final Stage primaryStage;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.*;
public MainModule(Properties properties, Stage primaryStage) {
super(properties);
this.primaryStage = primaryStage;
public class BitsquareEnvironmentTests {
@Test
public void test() {
String[] args = new String[]{ "--arg1=val1", "--arg2=val2" };
OptionParser parser = new OptionParser();
parser.accepts("arg1").withRequiredArg();
parser.accepts("arg2").withRequiredArg();
BitsquareEnvironment env = new BitsquareEnvironment(parser.parse(args));
assertThat(env.getProperty("arg1"), equalTo("val1"));
assertThat(env.getProperty("arg2"), equalTo("val2"));
}
@Override
protected void configure() {
install(new AppModule(properties));
install(new GuiModule(properties, primaryStage));
}
}
}

View file

@ -17,7 +17,8 @@
package io.bitsquare.app.gui;
import io.bitsquare.gui.FatalException;
import io.bitsquare.BitsquareException;
import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.ViewLoader;
@ -34,7 +35,8 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static io.bitsquare.app.AppModule.APP_NAME_KEY;
import joptsimple.OptionParser;
import org.springframework.core.env.PropertiesPropertySource;
public class ViewLoaderTests {
@ -64,8 +66,11 @@ public class ViewLoaderTests {
@Before
public void setUp() {
Properties properties = new Properties();
properties.setProperty(APP_NAME_KEY, "testApp");
Injector injector = Guice.createInjector(new MainModule(properties, TestApp.primaryStage));
properties.setProperty(BitsquareEnvironment.APP_NAME_KEY, "testApp");
OptionParser parser = new OptionParser();
BitsquareEnvironment env = new BitsquareEnvironment(parser.parse(new String[] {}));
env.getPropertySources().addLast(new PropertiesPropertySource("testProperties", properties));
Injector injector = Guice.createInjector(new BitsquareAppModule(env, TestApp.primaryStage));
ViewLoader.setInjector(injector);
}
@ -74,7 +79,7 @@ public class ViewLoaderTests {
ViewLoader.setInjector(null);
}
@Test(expected = FatalException.class)
@Test(expected = BitsquareException.class)
public void loadingBogusFxmlResourceShouldThrow() {
new ViewLoader(() -> "a bogus fxml resource", false).load();
}