From 917dd3522b6bab2268fd01419fe488b2d60a739a Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Tue, 24 Mar 2015 17:16:34 +0100 Subject: [PATCH] Refactor persistence (add Storage class) --- core/pom.xml | 11 ++ .../java/io/bitsquare/app/BitsquareApp.java | 15 +- .../io/bitsquare/app/BitsquareAppModule.java | 4 + .../bitsquare/app/BitsquareEnvironment.java | 7 +- .../java/io/bitsquare/btc/AddressEntry.java | 18 +- .../io/bitsquare/btc/AddressEntryList.java | 85 +++++++++ .../java/io/bitsquare/btc/WalletService.java | 45 +---- .../common/viewfx/view/ViewPath.java | 10 +- .../bitsquare/crypto/EncryptionService.java | 8 +- .../java/io/bitsquare/fiat/FiatAccount.java | 4 +- .../java/io/bitsquare/gui/Navigation.java | 65 ++++--- .../java/io/bitsquare/gui/main/MainView.java | 2 +- .../io/bitsquare/gui/main/MainViewModel.java | 71 ++++---- .../ArbitratorRegistrationView.java | 3 +- .../content/fiat/FiatAccountDataModel.java | 12 +- .../content/irc/IrcAccountDataModel.java | 50 +----- .../registration/RegistrationDataModel.java | 1 - .../restrictions/RestrictionsDataModel.java | 60 +------ .../funds/withdrawal/WithdrawalListItem.java | 2 +- .../application/PreferencesDataModel.java | 2 +- .../createoffer/CreateOfferDataModel.java | 4 +- .../trade/offerbook/OfferBookDataModel.java | 10 +- .../io/bitsquare/gui/util/BSFormatter.java | 8 +- .../gui/util/validation/FiatValidator.java | 8 +- .../validation/OptionalFiatValidator.java | 8 +- .../io/bitsquare/locale/LanguageUtil.java | 5 +- .../java/io/bitsquare/offer/OfferBook.java | 6 +- .../io/bitsquare/persistence/Persistence.java | 37 ++-- .../io/bitsquare/persistence/Storage.java | 84 +++++++++ .../java/io/bitsquare/trade/Contract.java | 6 +- .../java/io/bitsquare/trade/TradeManager.java | 4 +- .../offerer/models/OffererAsBuyerModel.java | 2 +- .../taker/models/TakerAsSellerModel.java | 2 +- .../io/bitsquare/user/AccountSettings.java | 42 +++-- .../java/io/bitsquare/user/Preferences.java | 145 +++++++--------- .../src/main/java/io/bitsquare/user/User.java | 163 ++++++++++-------- .../java/io/bitsquare/util/DSAKeyUtil.java | 49 ------ .../main/java/io/bitsquare/util/FileUtil.java | 120 +++++++++++++ .../java/io/bitsquare/util/Utilities.java | 10 ++ .../crypto/EncryptionServiceTests.java | 8 +- .../placeoffer/PlaceOfferProtocolTest.java | 27 +-- pom.xml | 17 -- 42 files changed, 692 insertions(+), 548 deletions(-) create mode 100644 core/src/main/java/io/bitsquare/btc/AddressEntryList.java create mode 100644 core/src/main/java/io/bitsquare/persistence/Storage.java delete mode 100755 core/src/main/java/io/bitsquare/util/DSAKeyUtil.java create mode 100644 core/src/main/java/io/bitsquare/util/FileUtil.java diff --git a/core/pom.xml b/core/pom.xml index 8eb7c83eeb..0ab7ee3784 100755 --- a/core/pom.xml +++ b/core/pom.xml @@ -104,11 +104,22 @@ logback-classic 1.1.2 + + org.bitcoinj + bitcoinj-core + 0.13.d13665c-SNAPSHOT + net.tomp2p tomp2p-all 5.0-Beta3 + + com.google.guava + guava + 16.0.1 + + io.reactivex rxjava diff --git a/core/src/main/java/io/bitsquare/app/BitsquareApp.java b/core/src/main/java/io/bitsquare/app/BitsquareApp.java index 21cac03c03..96036729aa 100644 --- a/core/src/main/java/io/bitsquare/app/BitsquareApp.java +++ b/core/src/main/java/io/bitsquare/app/BitsquareApp.java @@ -27,8 +27,6 @@ import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.debug.DebugView; import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.persistence.Persistence; -import io.bitsquare.user.AccountSettings; -import io.bitsquare.user.User; import io.bitsquare.util.Utilities; import com.google.common.base.Throwables; @@ -72,11 +70,11 @@ public class BitsquareApp extends Application { this.primaryStage = primaryStage; log.trace("BitsquareApp.start"); - + bitsquareAppModule = new BitsquareAppModule(env, primaryStage); injector = Guice.createInjector(bitsquareAppModule); injector.getInstance(InjectorViewFactory.class).setInjector(injector); - + // route uncaught exceptions to a user-facing dialog Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> @@ -84,17 +82,10 @@ public class BitsquareApp extends Application { // load and apply any stored settings - User user = injector.getInstance(User.class); - AccountSettings accountSettings = injector.getInstance(AccountSettings.class); + Persistence persistence = injector.getInstance(Persistence.class); persistence.init(); - User persistedUser = (User) persistence.read(user); - user.applyPersistedUser(persistedUser); - - accountSettings.applyPersistedAccountSettings((AccountSettings) persistence - .read(accountSettings.getClass().getName())); - // load the main view and create the main scene log.trace("viewLoader.load(MainView.class)"); diff --git a/core/src/main/java/io/bitsquare/app/BitsquareAppModule.java b/core/src/main/java/io/bitsquare/app/BitsquareAppModule.java index b4aba5924c..350b5008a8 100644 --- a/core/src/main/java/io/bitsquare/app/BitsquareAppModule.java +++ b/core/src/main/java/io/bitsquare/app/BitsquareAppModule.java @@ -28,6 +28,7 @@ import io.bitsquare.p2p.tomp2p.TomP2PModule; import io.bitsquare.offer.OfferModule; import io.bitsquare.offer.tomp2p.TomP2POfferModule; import io.bitsquare.persistence.Persistence; +import io.bitsquare.persistence.Storage; import io.bitsquare.trade.TradeModule; import io.bitsquare.user.AccountSettings; import io.bitsquare.user.Preferences; @@ -59,6 +60,9 @@ class BitsquareAppModule extends BitsquareModule { bind(Preferences.class).in(Singleton.class); bind(AccountSettings.class).in(Singleton.class); + File storageDir = new File(env.getRequiredProperty(Storage.DIR_KEY)); + bind(File.class).annotatedWith(named(Storage.DIR_KEY)).toInstance(storageDir); + File persistenceDir = new File(env.getRequiredProperty(Persistence.DIR_KEY)); bind(File.class).annotatedWith(named(Persistence.DIR_KEY)).toInstance(persistenceDir); bindConstant().annotatedWith(named(Persistence.PREFIX_KEY)).to(env.getRequiredProperty(Persistence.PREFIX_KEY)); diff --git a/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java b/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java index 8357dbd4bf..4221046164 100644 --- a/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java +++ b/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java @@ -22,6 +22,7 @@ import io.bitsquare.btc.UserAgent; import io.bitsquare.btc.WalletService; import io.bitsquare.gui.main.MainView; import io.bitsquare.persistence.Persistence; +import io.bitsquare.persistence.Storage; import io.bitsquare.util.Utilities; import io.bitsquare.util.spring.JOptCommandLinePropertySource; @@ -134,9 +135,11 @@ public class BitsquareEnvironment extends StandardEnvironment { setProperty(WalletService.DIR_KEY, appDataDir); setProperty(WalletService.PREFIX_KEY, appName); - setProperty(Persistence.DIR_KEY, appDataDir); + setProperty(Storage.DIR_KEY, Paths.get(appDataDir, "db").toString()); + + setProperty(Persistence.DIR_KEY, appDataDir); setProperty(Persistence.PREFIX_KEY, appName + "_pref"); - + setProperty(MainView.TITLE_KEY, appName); }}); } diff --git a/core/src/main/java/io/bitsquare/btc/AddressEntry.java b/core/src/main/java/io/bitsquare/btc/AddressEntry.java index 84caafe43c..ada686630c 100644 --- a/core/src/main/java/io/bitsquare/btc/AddressEntry.java +++ b/core/src/main/java/io/bitsquare/btc/AddressEntry.java @@ -33,20 +33,20 @@ public class AddressEntry implements Serializable { private static final long serialVersionUID = 5501603992599920416L; private final String offerId; - private final AddressContext addressContext; + private final Context context; private transient DeterministicKey keyPair; private final byte[] pubKey; private final byte[] pubKeyHash; private final NetworkParameters params; - public AddressEntry(DeterministicKey keyPair, NetworkParameters params, @SuppressWarnings("SameParameterValue") AddressContext addressContext) { - this(keyPair, params, addressContext, null); + public AddressEntry(DeterministicKey keyPair, NetworkParameters params, @SuppressWarnings("SameParameterValue") Context context) { + this(keyPair, params, context, null); } - public AddressEntry(DeterministicKey keyPair, NetworkParameters params, AddressContext addressContext, String offerId) { + public AddressEntry(DeterministicKey keyPair, NetworkParameters params, Context context, String offerId) { this.keyPair = keyPair; this.params = params; - this.addressContext = addressContext; + this.context = context; this.offerId = offerId; pubKey = keyPair.getPubKey(); @@ -57,8 +57,8 @@ public class AddressEntry implements Serializable { return offerId; } - public AddressContext getAddressContext() { - return addressContext; + public Context getContext() { + return context; } public String getAddressString() { @@ -85,7 +85,7 @@ public class AddressEntry implements Serializable { return pubKey; } - public static enum AddressContext { + public static enum Context { REGISTRATION_FEE, TRADE, ARBITRATOR_DEPOSIT @@ -95,7 +95,7 @@ public class AddressEntry implements Serializable { public String toString() { return "AddressEntry{" + "offerId='" + offerId + - ", addressContext=" + addressContext + + ", addressContext=" + context + ", keyPair=" + keyPair + ", pubKey=" + Arrays.toString(pubKey) + ", pubKeyHash=" + Arrays.toString(pubKeyHash) + diff --git a/core/src/main/java/io/bitsquare/btc/AddressEntryList.java b/core/src/main/java/io/bitsquare/btc/AddressEntryList.java new file mode 100644 index 0000000000..56b1d6997e --- /dev/null +++ b/core/src/main/java/io/bitsquare/btc/AddressEntryList.java @@ -0,0 +1,85 @@ +/* + * 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 . + */ + +package io.bitsquare.btc; + +import io.bitsquare.persistence.Storage; + +import org.bitcoinj.core.Wallet; +import org.bitcoinj.crypto.DeterministicKey; + +import com.google.inject.Inject; + +import java.io.Serializable; + +import java.util.ArrayList; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AddressEntryList extends ArrayList implements Serializable { + private static final long serialVersionUID = 1L; + transient private static final Logger log = LoggerFactory.getLogger(AddressEntryList.class); + + transient private Storage storage; + transient private Wallet wallet; + + // Persisted fields are in ArrayList superclass + + @Inject + public AddressEntryList(Storage storage) { + this.storage = storage; + } + + public void init(Wallet wallet) { + this.wallet = wallet; + + AddressEntryList persisted = storage.getPersisted(this); + if (persisted != null) { + for (AddressEntry addressEntry : persisted) { + addressEntry.setDeterministicKey((DeterministicKey) wallet.findKeyFromPubHash(addressEntry.getPubKeyHash())); + } + } + else { + // First time create registrationAddressEntry + createRegistrationAddressEntry(); + } + } + + public AddressEntry getNewAddressEntry(AddressEntry.Context context, String offerId) { + log.trace("getNewAddressEntry called with offerId " + offerId); + DeterministicKey key = wallet.freshReceiveKey(); + AddressEntry addressEntry = new AddressEntry(key, wallet.getParams(), context, offerId); + add(addressEntry); + storage.save(); + return addressEntry; + } + + private void createRegistrationAddressEntry() { + DeterministicKey registrationKey = wallet.currentReceiveKey(); + AddressEntry registrationAddressEntry = new AddressEntry(registrationKey, wallet.getParams(), AddressEntry.Context.REGISTRATION_FEE); + add(registrationAddressEntry); + storage.save(); + } + + public AddressEntry getRegistrationAddressEntry() { + if (isEmpty()) + createRegistrationAddressEntry(); + + return get(0); + } +} diff --git a/core/src/main/java/io/bitsquare/btc/WalletService.java b/core/src/main/java/io/bitsquare/btc/WalletService.java index e05ffd6975..76acee872d 100644 --- a/core/src/main/java/io/bitsquare/btc/WalletService.java +++ b/core/src/main/java/io/bitsquare/btc/WalletService.java @@ -36,7 +36,6 @@ import org.bitcoinj.core.TransactionInput; import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.Wallet; import org.bitcoinj.core.WalletEventListener; -import org.bitcoinj.crypto.DeterministicKey; import org.bitcoinj.kits.WalletAppKit; import org.bitcoinj.params.MainNetParams; import org.bitcoinj.params.RegTestParams; @@ -50,7 +49,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Service; import java.io.File; -import java.io.Serializable; import java.util.ArrayList; import java.util.Date; @@ -97,12 +95,13 @@ public class WalletService { private final File walletDir; private final String walletPrefix; private final UserAgent userAgent; + private final BitcoinNetwork bitcoinNetwork; private WalletAppKit walletAppKit; private Wallet wallet; private AddressEntry registrationAddressEntry; private AddressEntry arbitratorDepositAddressEntry; - private List addressEntryList = new ArrayList<>(); + private AddressEntryList addressEntryList; private TradeWalletService tradeWalletService; @@ -112,8 +111,10 @@ public class WalletService { @Inject public WalletService(BitcoinNetwork bitcoinNetwork, FeePolicy feePolicy, SignatureService signatureService, - Persistence persistence, UserAgent userAgent, + Persistence persistence, AddressEntryList addressEntryList, UserAgent userAgent, @Named(DIR_KEY) File walletDir, @Named(PREFIX_KEY) String walletPrefix) { + this.bitcoinNetwork = bitcoinNetwork; + this.addressEntryList = addressEntryList; this.params = bitcoinNetwork.getParameters(); this.feePolicy = feePolicy; this.signatureService = signatureService; @@ -204,23 +205,8 @@ public class WalletService { wallet = walletAppKit.wallet(); wallet.addEventListener(walletEventListener); - Serializable serializable = persistence.read(this, "addressEntryList"); - if (serializable instanceof List) { - List persistedAddressEntryList = (List) serializable; - for (AddressEntry persistedAddressEntry : persistedAddressEntryList) { - persistedAddressEntry.setDeterministicKey((DeterministicKey) wallet.findKeyFromPubHash(persistedAddressEntry.getPubKeyHash())); - } - addressEntryList = persistedAddressEntryList; - registrationAddressEntry = addressEntryList.get(0); - } - else { - // First time - DeterministicKey registrationKey = wallet.currentReceiveKey(); - registrationAddressEntry = new AddressEntry(registrationKey, params, - AddressEntry.AddressContext.REGISTRATION_FEE); - addressEntryList.add(registrationAddressEntry); - saveAddressInfoList(); - } + addressEntryList.init(wallet); + registrationAddressEntry = addressEntryList.getRegistrationAddressEntry(); } public void shutDown() { @@ -285,7 +271,7 @@ public class WalletService { public AddressEntry getArbitratorDepositAddressEntry() { if (arbitratorDepositAddressEntry == null) - arbitratorDepositAddressEntry = getNewAddressEntry(AddressEntry.AddressContext.ARBITRATOR_DEPOSIT, null); + arbitratorDepositAddressEntry = addressEntryList.getNewAddressEntry(AddressEntry.Context.ARBITRATOR_DEPOSIT, null); return arbitratorDepositAddressEntry; } @@ -297,7 +283,7 @@ public class WalletService { if (addressEntry.isPresent()) return addressEntry.get(); else - return getNewAddressEntry(AddressEntry.AddressContext.TRADE, offerId); + return addressEntryList.getNewAddressEntry(AddressEntry.Context.TRADE, offerId); } @@ -305,15 +291,6 @@ public class WalletService { // Create new AddressInfo objects /////////////////////////////////////////////////////////////////////////////////////////// - private AddressEntry getNewAddressEntry(AddressEntry.AddressContext addressContext, String offerId) { - log.trace("getNewAddressEntry called with offerId " + offerId); - DeterministicKey key = wallet.freshReceiveKey(); - AddressEntry addressEntry = new AddressEntry(key, params, addressContext, offerId); - addressEntryList.add(addressEntry); - saveAddressInfoList(); - return addressEntry; - } - private Optional getAddressEntryByAddressString(String address) { return getAddressEntryList().stream().filter(e -> address.equals(e.getAddressString())).findFirst(); } @@ -541,10 +518,6 @@ public class WalletService { // Private methods /////////////////////////////////////////////////////////////////////////////////////////// - private void saveAddressInfoList() { - persistence.write(this, "addressEntryList", addressEntryList); - } - private static void printTxWithInputs(String tracePrefix, Transaction tx) { log.trace(tracePrefix + ": " + tx.toString()); for (TransactionInput input : tx.getInputs()) { diff --git a/core/src/main/java/io/bitsquare/common/viewfx/view/ViewPath.java b/core/src/main/java/io/bitsquare/common/viewfx/view/ViewPath.java index c6ea99e88b..77aa53c10e 100644 --- a/core/src/main/java/io/bitsquare/common/viewfx/view/ViewPath.java +++ b/core/src/main/java/io/bitsquare/common/viewfx/view/ViewPath.java @@ -17,14 +17,22 @@ package io.bitsquare.common.viewfx.view; +import java.io.Serializable; + import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; -public class ViewPath extends ArrayList> { +public class ViewPath extends ArrayList> implements Serializable { + private static final long serialVersionUID = 1L; public ViewPath() { } + public ViewPath(Collection> c) { + super(c); + } + public static ViewPath to(Class... elements) { ViewPath path = new ViewPath(); path.addAll(Arrays.asList(elements)); diff --git a/core/src/main/java/io/bitsquare/crypto/EncryptionService.java b/core/src/main/java/io/bitsquare/crypto/EncryptionService.java index ce0f79b22a..a2496cf9bb 100644 --- a/core/src/main/java/io/bitsquare/crypto/EncryptionService.java +++ b/core/src/main/java/io/bitsquare/crypto/EncryptionService.java @@ -54,7 +54,13 @@ public class EncryptionService { public EncryptionService() { } - public KeyPair getKeyPair() throws NoSuchAlgorithmException { + public KeyPair getGeneratedDSAKeyPair() throws NoSuchAlgorithmException { + final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA"); + keyPairGenerator.initialize(1024); + return keyPairGenerator.genKeyPair(); + } + + public KeyPair getGeneratedRSAKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGO_ASYM); keyPairGenerator.initialize(KEY_SIZE_ASYM); return keyPairGenerator.genKeyPair(); diff --git a/core/src/main/java/io/bitsquare/fiat/FiatAccount.java b/core/src/main/java/io/bitsquare/fiat/FiatAccount.java index a27011fc5c..3c3cb30664 100644 --- a/core/src/main/java/io/bitsquare/fiat/FiatAccount.java +++ b/core/src/main/java/io/bitsquare/fiat/FiatAccount.java @@ -88,7 +88,7 @@ public class FiatAccount implements Serializable { } // we use the accountTitle as unique id - public String getUid() { + public String getId() { return nameOfBank; } @@ -112,7 +112,7 @@ public class FiatAccount implements Serializable { if (obj == this) return true; final FiatAccount other = (FiatAccount) obj; - return nameOfBank.equals(other.getUid()); + return nameOfBank.equals(other.getId()); } @Override diff --git a/core/src/main/java/io/bitsquare/gui/Navigation.java b/core/src/main/java/io/bitsquare/gui/Navigation.java index f02a3153e3..67460646f1 100644 --- a/core/src/main/java/io/bitsquare/gui/Navigation.java +++ b/core/src/main/java/io/bitsquare/gui/Navigation.java @@ -21,7 +21,7 @@ import io.bitsquare.common.viewfx.view.View; import io.bitsquare.common.viewfx.view.ViewPath; import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.trade.BuyView; -import io.bitsquare.persistence.Persistence; +import io.bitsquare.persistence.Storage; import com.google.inject.Inject; @@ -31,28 +31,46 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -public class Navigation { +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; - private static final String CURRENT_PATH_KEY = "currentPath"; +public class Navigation implements Serializable { + private static final long serialVersionUID = 1L; + transient private static final Logger log = LoggerFactory.getLogger(Navigation.class); - private static final ViewPath DEFAULT_VIEW_PATH = ViewPath.to(MainView.class, BuyView.class); + transient private static final ViewPath DEFAULT_VIEW_PATH = ViewPath.to(MainView.class, BuyView.class); + + + public interface Listener { + void onNavigationRequested(ViewPath path); + } // New listeners can be added during iteration so we use CopyOnWriteArrayList to // prevent invalid array modification - private final List listeners = new CopyOnWriteArrayList<>(); - - private final Persistence persistence; - - private ViewPath currentPath; - + transient private final List listeners = new CopyOnWriteArrayList<>(); + transient private final Storage storage; + transient private ViewPath currentPath; // Used for returning to the last important view. After setup is done we want to // return to the last opened view (e.g. sell/buy) - private ViewPath returnPath; + transient private ViewPath returnPath; + + // Persisted fields + private ViewPath previousPath; @Inject - public Navigation(Persistence persistence) { - this.persistence = persistence; + public Navigation(Storage storage) { + this.storage = storage; + + Navigation persisted = storage.getPersisted(this); + if (persisted != null) { + previousPath = persisted.getPreviousPath(); + } + else + previousPath = DEFAULT_VIEW_PATH; + + // need to be null initially and not DEFAULT_VIEW_PATH to navigate through all items + currentPath = null; } public void navigateTo(Class... viewClasses) { @@ -84,21 +102,16 @@ public class Navigation { } currentPath = newPath; - persistence.write(this, CURRENT_PATH_KEY, (List) currentPath); + previousPath = currentPath; + storage.save(); listeners.stream().forEach((e) -> e.onNavigationRequested(currentPath)); } - public void navigateToLastOpenView() { - ViewPath lastPath = (ViewPath) persistence.read(this, CURRENT_PATH_KEY); + public void navigateToPreviousVisitedView() { + if (previousPath == null || previousPath.size() == 0) + previousPath = DEFAULT_VIEW_PATH; - if (lastPath == null || lastPath.size() == 0) - lastPath = DEFAULT_VIEW_PATH; - - navigateTo(lastPath); - } - - public static interface Listener { - void onNavigationRequested(ViewPath path); + navigateTo(previousPath); } public void addListener(Listener listener) { @@ -120,4 +133,8 @@ public class Navigation { public void setReturnPath(ViewPath returnPath) { this.returnPath = returnPath; } + + private ViewPath getPreviousPath() { + return previousPath; + } } diff --git a/core/src/main/java/io/bitsquare/gui/main/MainView.java b/core/src/main/java/io/bitsquare/gui/main/MainView.java index f55e4eeb53..89f501123f 100644 --- a/core/src/main/java/io/bitsquare/gui/main/MainView.java +++ b/core/src/main/java/io/bitsquare/gui/main/MainView.java @@ -154,7 +154,7 @@ public class MainView extends InitializableView { if (newValue) { bankAccountComboBoxHolder.getChildren().setAll(createBankAccountComboBox()); - navigation.navigateToLastOpenView(); + navigation.navigateToPreviousVisitedView(); transitions.fadeOutAndRemove(splashScreen, 1500); } diff --git a/core/src/main/java/io/bitsquare/gui/main/MainViewModel.java b/core/src/main/java/io/bitsquare/gui/main/MainViewModel.java index 49266adf54..ba3c3e81b0 100644 --- a/core/src/main/java/io/bitsquare/gui/main/MainViewModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/MainViewModel.java @@ -38,7 +38,7 @@ import io.bitsquare.trade.Trade; import io.bitsquare.trade.TradeManager; import io.bitsquare.user.AccountSettings; import io.bitsquare.user.User; -import io.bitsquare.util.DSAKeyUtil; +import io.bitsquare.util.Utilities; import org.bitcoinj.core.Coin; import org.bitcoinj.core.ECKey; @@ -129,14 +129,14 @@ class MainViewModel implements ViewModel { updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue)); applyUpdateState(updateProcess.state.get()); - user.getCurrentBankAccount().addListener((observable, oldValue, newValue) -> persistence.write(user)); - currentBankAccount.bind(user.currentBankAccountProperty()); - user.getFiatAccounts().addListener((ListChangeListener) change -> { + user.currentFiatAccountProperty().addListener((observable, oldValue, newValue) -> persistence.write(user)); + currentBankAccount.bind(user.currentFiatAccountProperty()); + user.fiatAccountsObservableList().addListener((ListChangeListener) change -> { bankAccountsComboBoxDisable.set(change.getList().isEmpty()); bankAccountsComboBoxPrompt.set(change.getList().isEmpty() ? "No accounts" : ""); }); - bankAccountsComboBoxDisable.set(user.getFiatAccounts().isEmpty()); - bankAccountsComboBoxPrompt.set(user.getFiatAccounts().isEmpty() ? "No accounts" : ""); + bankAccountsComboBoxDisable.set(user.fiatAccountsObservableList().isEmpty()); + bankAccountsComboBoxPrompt.set(user.fiatAccountsObservableList().isEmpty() ? "No accounts" : ""); } public void restart() { @@ -214,7 +214,7 @@ class MainViewModel implements ViewModel { // For alpha version // uses messageService, so don't call it before backend is ready if (accountSettings.getAcceptedArbitrators().isEmpty()) - addMockArbitrator(); + accountSettings.addAcceptedArbitrator(getMockArbitrator()); // For alpha version if (!user.isRegistered()) { @@ -225,11 +225,10 @@ class MainViewModel implements ViewModel { "Demo (Account holder name)", "Demo (E.g. IBAN) ", "Demo (E.g. BIC) "); - user.setBankAccount(fiatAccount); + user.addFiatAccount(fiatAccount); persistence.write(user); user.setAccountID(walletService.getRegistrationAddressEntry().toString()); - persistence.write(user.getClass().getName(), user); } tradeManager.onAllServicesInitialized(); @@ -321,11 +320,11 @@ class MainViewModel implements ViewModel { } public ObservableList getBankAccounts() { - return user.getFiatAccounts(); + return user.fiatAccountsObservableList(); } public void setCurrentBankAccount(FiatAccount currentFiatAccount) { - user.setCurrentBankAccount(currentFiatAccount); + user.setCurrentFiatAccount(currentFiatAccount); } private void updateNumPendingTrades() { @@ -352,34 +351,30 @@ class MainViewModel implements ViewModel { } } - private void addMockArbitrator() { - if (accountSettings.getAcceptedArbitrators().isEmpty() && user.getP2pSigKeyPair() != null) { - byte[] pubKey = new ECKey().getPubKey(); - String p2pSigPubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getP2PSigPubKey()); - List languages = new ArrayList<>(); - languages.add(LanguageUtil.getDefaultLanguageLocale()); - List arbitrationMethods = new ArrayList<>(); - arbitrationMethods.add(Arbitrator.METHOD.TLS_NOTARY); - List idVerifications = new ArrayList<>(); - idVerifications.add(Arbitrator.ID_VERIFICATION.PASSPORT); - idVerifications.add(Arbitrator.ID_VERIFICATION.GOV_ID); + private Arbitrator getMockArbitrator() { + byte[] pubKey = new ECKey().getPubKey(); + String p2pSigPubKeyAsHex = Utilities.getHexStringFromPublicKey(user.getP2PSigPubKey()); + List languages = new ArrayList<>(); + languages.add(LanguageUtil.getDefaultLanguageLocale()); + List arbitrationMethods = new ArrayList<>(); + arbitrationMethods.add(Arbitrator.METHOD.TLS_NOTARY); + List idVerifications = new ArrayList<>(); + idVerifications.add(Arbitrator.ID_VERIFICATION.PASSPORT); + idVerifications.add(Arbitrator.ID_VERIFICATION.GOV_ID); - Arbitrator arbitrator = new Arbitrator(pubKey, - p2pSigPubKeyAsHex, - "Manfred Karrer", - Arbitrator.ID_TYPE.REAL_LIFE_ID, - languages, - new Reputation(), - Coin.parseCoin("0.1"), - arbitrationMethods, - idVerifications, - "https://bitsquare.io", - "Bla bla..."); + Arbitrator arbitrator = new Arbitrator(pubKey, + p2pSigPubKeyAsHex, + "Manfred Karrer", + Arbitrator.ID_TYPE.REAL_LIFE_ID, + languages, + new Reputation(), + Coin.parseCoin("0.1"), + arbitrationMethods, + idVerifications, + "https://bitsquare.io", + "Bla bla..."); - accountSettings.addAcceptedArbitrator(arbitrator); - persistence.write(accountSettings); - - arbitratorService.addArbitrator(arbitrator); - } + arbitratorService.addArbitrator(arbitrator); + return arbitrator; } } diff --git a/core/src/main/java/io/bitsquare/gui/main/account/arbitrator/registration/ArbitratorRegistrationView.java b/core/src/main/java/io/bitsquare/gui/main/account/arbitrator/registration/ArbitratorRegistrationView.java index 2b9ee11c5d..fcae9d2e89 100644 --- a/core/src/main/java/io/bitsquare/gui/main/account/arbitrator/registration/ArbitratorRegistrationView.java +++ b/core/src/main/java/io/bitsquare/gui/main/account/arbitrator/registration/ArbitratorRegistrationView.java @@ -29,7 +29,6 @@ import io.bitsquare.locale.BSResources; import io.bitsquare.locale.LanguageUtil; import io.bitsquare.persistence.Persistence; import io.bitsquare.user.User; -import io.bitsquare.util.DSAKeyUtil; import io.bitsquare.util.Utilities; import org.bitcoinj.core.Coin; @@ -369,7 +368,7 @@ public class ArbitratorRegistrationView extends ActivatableView languages = new ArrayList<>(); - languages.add(LanguageUtil.getDefaultLanguageLocale()); - List arbitrationMethods = new ArrayList<>(); - arbitrationMethods.add(Arbitrator.METHOD.TLS_NOTARY); - List idVerifications = new ArrayList<>(); - idVerifications.add(Arbitrator.ID_VERIFICATION.PASSPORT); - idVerifications.add(Arbitrator.ID_VERIFICATION.GOV_ID); - - Arbitrator arbitrator = new Arbitrator(pubKey, - p2pSigPubKeyAsHex, - "Manfred Karrer", - Arbitrator.ID_TYPE.REAL_LIFE_ID, - languages, - new Reputation(), - Coin.parseCoin("0.001"), - arbitrationMethods, - idVerifications, - "https://bitsquare.io/", - "Bla bla..."); - - accountSettings.addAcceptedArbitrator(arbitrator); - persistence.write(accountSettings); - - messageService.addArbitrator(arbitrator); - } - } } diff --git a/core/src/main/java/io/bitsquare/gui/main/account/content/registration/RegistrationDataModel.java b/core/src/main/java/io/bitsquare/gui/main/account/content/registration/RegistrationDataModel.java index 93bfc972b0..8edea8a912 100644 --- a/core/src/main/java/io/bitsquare/gui/main/account/content/registration/RegistrationDataModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/account/content/registration/RegistrationDataModel.java @@ -91,7 +91,6 @@ class RegistrationDataModel implements DataModel { if (getAddressEntry() != null) user.setAccountID(getAddressEntry().toString()); - persistence.write(user.getClass().getName(), user); payFeeSuccess.set(true); } } diff --git a/core/src/main/java/io/bitsquare/gui/main/account/content/restrictions/RestrictionsDataModel.java b/core/src/main/java/io/bitsquare/gui/main/account/content/restrictions/RestrictionsDataModel.java index fa1d166f78..21903a8ef2 100644 --- a/core/src/main/java/io/bitsquare/gui/main/account/content/restrictions/RestrictionsDataModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/account/content/restrictions/RestrictionsDataModel.java @@ -19,7 +19,6 @@ package io.bitsquare.gui.main.account.content.restrictions; import io.bitsquare.arbitration.Arbitrator; import io.bitsquare.arbitration.ArbitratorService; -import io.bitsquare.arbitration.Reputation; import io.bitsquare.common.viewfx.model.Activatable; import io.bitsquare.common.viewfx.model.DataModel; import io.bitsquare.locale.Country; @@ -29,15 +28,9 @@ import io.bitsquare.locale.Region; import io.bitsquare.persistence.Persistence; import io.bitsquare.user.AccountSettings; import io.bitsquare.user.User; -import io.bitsquare.util.DSAKeyUtil; - -import org.bitcoinj.core.Coin; -import org.bitcoinj.core.ECKey; import com.google.inject.Inject; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; import javafx.collections.FXCollections; @@ -65,28 +58,12 @@ class RestrictionsDataModel implements Activatable, DataModel { this.accountSettings = accountSettings; this.persistence = persistence; this.messageService = messageService; - - AccountSettings persistedAccountSettings = (AccountSettings) persistence.read(accountSettings); - if (persistedAccountSettings != null) { - accountSettings.applyPersistedAccountSettings(persistedAccountSettings); - } - else { - if (Locale.getDefault() != null) { - addLanguage(LanguageUtil.getDefaultLanguageLocale()); - addCountry(CountryUtil.getDefaultCountry()); - } - - // Add english as default as well - addLanguage(LanguageUtil.getEnglishLanguageLocale()); - } - - addMockArbitrator(); } @Override public void activate() { - languageList.setAll(accountSettings.getAcceptedLanguageLocales()); countryList.setAll(accountSettings.getAcceptedCountries()); + languageList.setAll(accountSettings.getAcceptedLanguageLocales()); arbitratorList.setAll(accountSettings.getAcceptedArbitrators()); } @@ -149,39 +126,4 @@ class RestrictionsDataModel implements Activatable, DataModel { private void saveSettings() { persistence.write(accountSettings); } - - // TODO Remove mock later - private void addMockArbitrator() { - if (accountSettings.getAcceptedArbitrators().isEmpty() && user.getP2pSigKeyPair() != null) { - byte[] pubKey = new ECKey().getPubKey(); - String p2pSigPubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getP2PSigPubKey()); - List languages = new ArrayList<>(); - languages.add(LanguageUtil.getDefaultLanguageLocale()); - List arbitrationMethods = new ArrayList<>(); - arbitrationMethods.add(Arbitrator.METHOD.TLS_NOTARY); - List idVerifications = new ArrayList<>(); - idVerifications.add(Arbitrator.ID_VERIFICATION.PASSPORT); - idVerifications.add(Arbitrator.ID_VERIFICATION.GOV_ID); - - // TODO use very small sec. dposit to make testing in testnet less expensive - // Revert later to 0.1 BTC again - Arbitrator arbitrator = new Arbitrator(pubKey, - p2pSigPubKeyAsHex, - "Manfred Karrer", - Arbitrator.ID_TYPE.REAL_LIFE_ID, - languages, - new Reputation(), - Coin.parseCoin("0.001"), - arbitrationMethods, - idVerifications, - "http://bitsquare.io/", - "Bla bla..."); - - arbitratorList.add(arbitrator); - accountSettings.addAcceptedArbitrator(arbitrator); - persistence.write(accountSettings); - - messageService.addArbitrator(arbitrator); - } - } } diff --git a/core/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalListItem.java b/core/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalListItem.java index 0b1e565635..0b9ca39899 100644 --- a/core/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalListItem.java +++ b/core/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalListItem.java @@ -127,7 +127,7 @@ public class WithdrawalListItem { public final String getLabel() { - switch (addressEntry.getAddressContext()) { + switch (addressEntry.getContext()) { case REGISTRATION_FEE: return "Registration fee"; case TRADE: diff --git a/core/src/main/java/io/bitsquare/gui/main/settings/application/PreferencesDataModel.java b/core/src/main/java/io/bitsquare/gui/main/settings/application/PreferencesDataModel.java index 36767c9fc6..c10b559d6c 100644 --- a/core/src/main/java/io/bitsquare/gui/main/settings/application/PreferencesDataModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/settings/application/PreferencesDataModel.java @@ -50,7 +50,7 @@ class PreferencesDataModel implements Activatable, DataModel { public PreferencesDataModel(Preferences preferences) { this.preferences = preferences; - btcDenominations = FXCollections.observableArrayList(preferences.getBtcDenominations()); + btcDenominations = FXCollections.observableArrayList(Preferences.getBtcDenominations()); btcDenominationListener = (ov, oldValue, newValue) -> preferences.setBtcDenomination(newValue); useAnimationsListener = (ov, oldValue, newValue) -> preferences.setUseAnimations(newValue); useEffectsListener = (ov, oldValue, newValue) -> preferences.setUseEffects(newValue); diff --git a/core/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferDataModel.java b/core/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferDataModel.java index 1b44e8c489..5dd5841754 100644 --- a/core/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferDataModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferDataModel.java @@ -137,9 +137,9 @@ class CreateOfferDataModel implements Activatable, DataModel { } if (user != null) { - user.currentBankAccountProperty().addListener((ov, oldValue, newValue) -> applyBankAccount(newValue)); + user.currentFiatAccountProperty().addListener((ov, oldValue, newValue) -> applyBankAccount(newValue)); - applyBankAccount(user.getCurrentBankAccount().get()); + applyBankAccount(user.currentFiatAccountProperty().get()); } if (accountSettings != null) diff --git a/core/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java b/core/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java index 48e47f9940..385171a7c9 100644 --- a/core/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java @@ -99,17 +99,17 @@ class OfferBookDataModel implements Activatable, DataModel { volumeAsFiat.set(null); offerBook.addClient(); - user.currentBankAccountProperty().addListener(bankAccountChangeListener); + user.currentFiatAccountProperty().addListener(bankAccountChangeListener); btcCode.bind(preferences.btcDenominationProperty()); - setBankAccount(user.getCurrentBankAccount().get()); + setBankAccount(user.currentFiatAccountProperty().get()); applyFilter(); } @Override public void deactivate() { offerBook.removeClient(); - user.currentBankAccountProperty().removeListener(bankAccountChangeListener); + user.currentFiatAccountProperty().removeListener(bankAccountChangeListener); btcCode.unbind(); } @@ -149,7 +149,7 @@ class OfferBookDataModel implements Activatable, DataModel { boolean isTradable(Offer offer) { // if user has not registered yet we display all - FiatAccount currentFiatAccount = user.getCurrentBankAccount().get(); + FiatAccount currentFiatAccount = user.currentFiatAccountProperty().get(); if (currentFiatAccount == null) return true; @@ -159,7 +159,7 @@ class OfferBookDataModel implements Activatable, DataModel { if (!countryResult) restrictionsInfo.set("This offer requires that the payments account resides in one of those countries:\n" + formatter.countryLocalesToString(offer.getAcceptedCountries()) + - "\n\nThe country of your payments account (" + user.getCurrentBankAccount().get().getCountry() + "\n\nThe country of your payments account (" + user.currentFiatAccountProperty().get().getCountry() .getName() + ") is not included in that list." + "\n\n Do you want to edit your preferences now?"); diff --git a/core/src/main/java/io/bitsquare/gui/util/BSFormatter.java b/core/src/main/java/io/bitsquare/gui/util/BSFormatter.java index 07dae4beb3..9a41289935 100644 --- a/core/src/main/java/io/bitsquare/gui/util/BSFormatter.java +++ b/core/src/main/java/io/bitsquare/gui/util/BSFormatter.java @@ -76,12 +76,12 @@ public class BSFormatter { @Inject public BSFormatter(User user) { - if (user.currentBankAccountProperty().get() == null) + if (user.currentFiatAccountProperty().get() == null) setFiatCurrencyCode(CurrencyUtil.getDefaultCurrency().getCurrencyCode()); - else if (user.currentBankAccountProperty().get() != null) - setFiatCurrencyCode(user.currentBankAccountProperty().get().getCurrency().getCurrencyCode()); + else if (user.currentFiatAccountProperty().get() != null) + setFiatCurrencyCode(user.currentFiatAccountProperty().get().getCurrency().getCurrencyCode()); - user.currentBankAccountProperty().addListener((ov, oldValue, newValue) -> { + user.currentFiatAccountProperty().addListener((ov, oldValue, newValue) -> { if (newValue != null) setFiatCurrencyCode(newValue.getCurrency().getCurrencyCode()); }); diff --git a/core/src/main/java/io/bitsquare/gui/util/validation/FiatValidator.java b/core/src/main/java/io/bitsquare/gui/util/validation/FiatValidator.java index 355753ff3b..e9d9a5d5b7 100644 --- a/core/src/main/java/io/bitsquare/gui/util/validation/FiatValidator.java +++ b/core/src/main/java/io/bitsquare/gui/util/validation/FiatValidator.java @@ -39,12 +39,12 @@ public final class FiatValidator extends NumberValidator { @Inject public FiatValidator(User user) { if (user != null) { - if (user.currentBankAccountProperty().get() == null) + if (user.currentFiatAccountProperty().get() == null) setFiatCurrencyCode(CurrencyUtil.getDefaultCurrency().getCurrencyCode()); - else if (user.currentBankAccountProperty().get() != null) - setFiatCurrencyCode(user.currentBankAccountProperty().get().getCurrency().getCurrencyCode()); + else if (user.currentFiatAccountProperty().get() != null) + setFiatCurrencyCode(user.currentFiatAccountProperty().get().getCurrency().getCurrencyCode()); - user.currentBankAccountProperty().addListener((ov, oldValue, newValue) -> { + user.currentFiatAccountProperty().addListener((ov, oldValue, newValue) -> { if (newValue != null) setFiatCurrencyCode(newValue.getCurrency().getCurrencyCode()); }); diff --git a/core/src/main/java/io/bitsquare/gui/util/validation/OptionalFiatValidator.java b/core/src/main/java/io/bitsquare/gui/util/validation/OptionalFiatValidator.java index 1201635c8c..cad9e42c39 100644 --- a/core/src/main/java/io/bitsquare/gui/util/validation/OptionalFiatValidator.java +++ b/core/src/main/java/io/bitsquare/gui/util/validation/OptionalFiatValidator.java @@ -39,12 +39,12 @@ public final class OptionalFiatValidator extends NumberValidator { @Inject public OptionalFiatValidator(User user) { if (user != null) { - if (user.currentBankAccountProperty().get() == null) + if (user.currentFiatAccountProperty().get() == null) setFiatCurrencyCode(CurrencyUtil.getDefaultCurrency().getCurrencyCode()); - else if (user.currentBankAccountProperty().get() != null) - setFiatCurrencyCode(user.currentBankAccountProperty().get().getCurrency().getCurrencyCode()); + else if (user.currentFiatAccountProperty().get() != null) + setFiatCurrencyCode(user.currentFiatAccountProperty().get().getCurrency().getCurrencyCode()); - user.currentBankAccountProperty().addListener((ov, oldValue, newValue) -> { + user.currentFiatAccountProperty().addListener((ov, oldValue, newValue) -> { if (newValue != null) setFiatCurrencyCode(newValue.getCurrency().getCurrencyCode()); }); diff --git a/core/src/main/java/io/bitsquare/locale/LanguageUtil.java b/core/src/main/java/io/bitsquare/locale/LanguageUtil.java index 5a0d7d7674..91e2b04c52 100644 --- a/core/src/main/java/io/bitsquare/locale/LanguageUtil.java +++ b/core/src/main/java/io/bitsquare/locale/LanguageUtil.java @@ -38,7 +38,10 @@ public class LanguageUtil { } public static Locale getDefaultLanguageLocale() { - return new Locale(Locale.getDefault().getLanguage(), ""); + if (Locale.getDefault() != null) + return new Locale(Locale.getDefault().getLanguage(), ""); + else + return getEnglishLanguageLocale(); } public static Locale getEnglishLanguageLocale() { diff --git a/core/src/main/java/io/bitsquare/offer/OfferBook.java b/core/src/main/java/io/bitsquare/offer/OfferBook.java index afb7a7eef2..5370cc3272 100644 --- a/core/src/main/java/io/bitsquare/offer/OfferBook.java +++ b/core/src/main/java/io/bitsquare/offer/OfferBook.java @@ -150,14 +150,14 @@ public class OfferBook { private void addListeners() { log.debug("addListeners "); - user.currentBankAccountProperty().addListener(bankAccountChangeListener); + user.currentFiatAccountProperty().addListener(bankAccountChangeListener); offerBookService.addListener(offerBookServiceListener); offerBookService.invalidationTimestampProperty().addListener(invalidationListener); } private void removeListeners() { log.debug("removeListeners "); - user.currentBankAccountProperty().removeListener(bankAccountChangeListener); + user.currentFiatAccountProperty().removeListener(bankAccountChangeListener); offerBookService.removeListener(offerBookServiceListener); offerBookService.invalidationTimestampProperty().removeListener(invalidationListener); } @@ -180,7 +180,7 @@ public class OfferBook { // TODO Just temporary, will be removed later when we have a push solution private void startPolling() { addListeners(); - setBankAccount(user.getCurrentBankAccount().get()); + setBankAccount(user.currentFiatAccountProperty().get()); pollingTimer = Utilities.setInterval(POLLING_INTERVAL, (animationTimer) -> { offerBookService.requestInvalidationTimeStampFromDHT(fiatCode); return null; diff --git a/core/src/main/java/io/bitsquare/persistence/Persistence.java b/core/src/main/java/io/bitsquare/persistence/Persistence.java index f427e749cf..e5775d2d05 100644 --- a/core/src/main/java/io/bitsquare/persistence/Persistence.java +++ b/core/src/main/java/io/bitsquare/persistence/Persistence.java @@ -96,36 +96,23 @@ public class Persistence { } // Map - public void write(String key, Map value) { - write(key, (Serializable) value); - } - - public void write(Object classInstance, String propertyKey, Map value) { - write(classInstance.getClass().getName() + "." + propertyKey, value); - } - - public void write(Object classInstance, Map value) { - write(classInstance.getClass().getName(), value); - } - - // List - public void write(String key, List value) { - write(key, (Serializable) value); - } - public void write(Object classInstance, String propertyKey, List value) { write(classInstance.getClass().getName() + "." + propertyKey, value); } - - public void write(Object classInstance, List value) { - write(classInstance.getClass().getName(), value); - } - - // Serializable public void write(Object classInstance, String propertyKey, Serializable value) { write(classInstance.getClass().getName() + "." + propertyKey, value); } + // not used outside + public void write(String key, Map value) { + write(key, (Serializable) value); + } + public void write(String key, List value) { + write(key, (Serializable) value); + } + + + // Serializable public void remove(Object classInstance, String propertyKey) { try { lock.lock(); @@ -136,9 +123,6 @@ public class Persistence { } } - public void write(Object classInstance, Serializable value) { - write(classInstance.getClass().getName(), value); - } public void write(Serializable classInstance) { write(classInstance.getClass().getName(), classInstance); @@ -311,4 +295,5 @@ public class Persistence { throw new IOException("Failed to rename " + tempFile + " to " + file); } } + } diff --git a/core/src/main/java/io/bitsquare/persistence/Storage.java b/core/src/main/java/io/bitsquare/persistence/Storage.java new file mode 100644 index 0000000000..e7dc6c24b9 --- /dev/null +++ b/core/src/main/java/io/bitsquare/persistence/Storage.java @@ -0,0 +1,84 @@ +/* + * 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 . + */ + +package io.bitsquare.persistence; + +import io.bitsquare.gui.components.Popups; +import io.bitsquare.util.FileUtil; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Serializable; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Storage { + private static final Logger log = LoggerFactory.getLogger(Storage.class); + + public static final String DIR_KEY = "storage.dir"; + private final File dir; + private File storageFile; + private T serializable; + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + @Inject + public Storage(@Named(DIR_KEY) File dir) { + this.dir = dir; + } + + public void save() { + if (storageFile == null) + throw new RuntimeException("storageFile = null. Call setupFileStorage before using read/write."); + + try { + FileUtil.write(serializable, dir, storageFile); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + Popups.openErrorPopup("An exception occurred at writing data to disc.", e.getMessage()); + } + } + + public T getPersisted(T serializable) { + this.serializable = serializable; + storageFile = new File(dir, serializable.getClass().getSimpleName() + ".ser"); + + if (storageFile == null) + throw new RuntimeException("storageFile = null. Call init before using read/write."); + + try { + return (T) FileUtil.read(storageFile); + } catch (FileNotFoundException e) { + log.info("File not available. That is OK for the first run."); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + log.error(e.getMessage()); + Popups.openErrorPopup("An exception occurred at reading data from disc.", e.getMessage()); + + } + return null; + } +} diff --git a/core/src/main/java/io/bitsquare/trade/Contract.java b/core/src/main/java/io/bitsquare/trade/Contract.java index a79d814dd7..2a67513413 100644 --- a/core/src/main/java/io/bitsquare/trade/Contract.java +++ b/core/src/main/java/io/bitsquare/trade/Contract.java @@ -19,7 +19,7 @@ package io.bitsquare.trade; import io.bitsquare.fiat.FiatAccount; import io.bitsquare.offer.Offer; -import io.bitsquare.util.DSAKeyUtil; +import io.bitsquare.util.Utilities; import org.bitcoinj.core.Coin; @@ -59,8 +59,8 @@ public class Contract implements Serializable { this.takerAccountID = takerAccountID; this.offererFiatAccount = offererFiatAccount; this.takerFiatAccount = takerFiatAccount; - this.offererP2PSigPubKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(offererP2PSigPubKey); - this.takerP2PSigPubKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(takerP2PSigPubKey); + this.offererP2PSigPubKeyAsString = Utilities.getHexStringFromPublicKey(offererP2PSigPubKey); + this.takerP2PSigPubKeyAsString = Utilities.getHexStringFromPublicKey(takerP2PSigPubKey); } diff --git a/core/src/main/java/io/bitsquare/trade/TradeManager.java b/core/src/main/java/io/bitsquare/trade/TradeManager.java index 1fd9e2f3a1..8e657d3ce1 100644 --- a/core/src/main/java/io/bitsquare/trade/TradeManager.java +++ b/core/src/main/java/io/bitsquare/trade/TradeManager.java @@ -174,7 +174,7 @@ public class TradeManager { TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - FiatAccount currentFiatAccount = user.getCurrentBankAccount().get(); + FiatAccount currentFiatAccount = user.currentFiatAccountProperty().get(); Offer offer = new Offer(id, user.getP2PSigPubKey(), direction, @@ -184,7 +184,7 @@ public class TradeManager { currentFiatAccount.getFiatAccountType(), currentFiatAccount.getCurrency(), currentFiatAccount.getCountry(), - currentFiatAccount.getUid(), + currentFiatAccount.getId(), accountSettings.getAcceptedArbitrators(), accountSettings.getSecurityDeposit(), accountSettings.getAcceptedCountries(), diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/offerer/models/OffererAsBuyerModel.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/offerer/models/OffererAsBuyerModel.java index 00b04cd762..01ddad375b 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/offerer/models/OffererAsBuyerModel.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/offerer/models/OffererAsBuyerModel.java @@ -79,7 +79,7 @@ public class OffererAsBuyerModel extends SharedTradeModel implements Serializabl offerer.registrationPubKey = walletService.getRegistrationAddressEntry().getPubKey(); offerer.registrationKeyPair = walletService.getRegistrationAddressEntry().getKeyPair(); offerer.addressEntry = walletService.getAddressEntry(id); - offerer.fiatAccount = user.getBankAccount(offer.getBankAccountId()); + offerer.fiatAccount = user.getFiatAccount(offer.getBankAccountId()); offerer.accountId = user.getAccountId(); offerer.p2pSigPubKey = user.getP2PSigPubKey(); offerer.p2pEncryptPubKey = user.getP2PEncryptPubKey(); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/taker/models/TakerAsSellerModel.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/taker/models/TakerAsSellerModel.java index 5bf623c9d6..4296232869 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/taker/models/TakerAsSellerModel.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/taker/models/TakerAsSellerModel.java @@ -83,7 +83,7 @@ public class TakerAsSellerModel extends SharedTradeModel implements Serializable taker.registrationPubKey = walletService.getRegistrationAddressEntry().getPubKey(); taker.registrationKeyPair = walletService.getRegistrationAddressEntry().getKeyPair(); taker.addressEntry = walletService.getAddressEntry(id); - taker.fiatAccount = user.getBankAccount(offer.getBankAccountId()); + taker.fiatAccount = user.getFiatAccount(offer.getBankAccountId()); taker.accountId = user.getAccountId(); taker.p2pSigPubKey = user.getP2PSigPubKey(); taker.p2pEncryptPublicKey = user.getP2PEncryptPubKey(); diff --git a/core/src/main/java/io/bitsquare/user/AccountSettings.java b/core/src/main/java/io/bitsquare/user/AccountSettings.java index 8f720595b3..4c29df9741 100644 --- a/core/src/main/java/io/bitsquare/user/AccountSettings.java +++ b/core/src/main/java/io/bitsquare/user/AccountSettings.java @@ -19,19 +19,28 @@ package io.bitsquare.user; import io.bitsquare.arbitration.Arbitrator; import io.bitsquare.locale.Country; +import io.bitsquare.locale.CountryUtil; +import io.bitsquare.locale.LanguageUtil; +import io.bitsquare.persistence.Storage; import org.bitcoinj.core.Coin; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.OptionalLong; -public class AccountSettings implements Serializable { - private static final long serialVersionUID = 7995048077355006861L; +import javax.inject.Inject; +public class AccountSettings implements Serializable { + private static final long serialVersionUID = 1L; + + transient private Storage storage; + + // Persisted fields private List acceptedLanguageLocales = new ArrayList<>(); private List acceptedCountryLocales = new ArrayList<>(); private List acceptedArbitrators = new ArrayList<>(); @@ -41,7 +50,21 @@ public class AccountSettings implements Serializable { // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - public AccountSettings() { + @Inject + public AccountSettings(Storage storage) { + this.storage = storage; + + AccountSettings persisted = storage.getPersisted(this); + if (persisted != null) { + acceptedLanguageLocales = persisted.getAcceptedLanguageLocales(); + acceptedCountryLocales = persisted.getAcceptedCountries(); + acceptedArbitrators = persisted.getAcceptedArbitrators(); + } + else { + acceptedLanguageLocales = Arrays.asList(LanguageUtil.getDefaultLanguageLocale(), LanguageUtil.getEnglishLanguageLocale()); + acceptedCountryLocales = Arrays.asList(CountryUtil.getDefaultCountry()); + acceptedArbitrators = new ArrayList<>(); + } } @@ -49,17 +72,11 @@ public class AccountSettings implements Serializable { // Public API /////////////////////////////////////////////////////////////////////////////////////////// - public void applyPersistedAccountSettings(AccountSettings persistedSettings) { - if (persistedSettings != null) { - acceptedLanguageLocales = persistedSettings.getAcceptedLanguageLocales(); - acceptedCountryLocales = persistedSettings.getAcceptedCountries(); - acceptedArbitrators = persistedSettings.getAcceptedArbitrators(); - } - } public void addAcceptedLanguageLocale(Locale locale) { if (!acceptedLanguageLocales.contains(locale)) { acceptedLanguageLocales.add(locale); + storage.save(); } } @@ -70,6 +87,7 @@ public class AccountSettings implements Serializable { public void addAcceptedCountry(Country locale) { if (!acceptedCountryLocales.contains(locale)) { acceptedCountryLocales.add(locale); + storage.save(); } } @@ -80,16 +98,18 @@ public class AccountSettings implements Serializable { public void addAcceptedArbitrator(Arbitrator arbitrator) { if (!acceptedArbitrators.contains(arbitrator)) { acceptedArbitrators.add(arbitrator); + storage.save(); } } public void removeAcceptedArbitrator(Arbitrator item) { acceptedArbitrators.remove(item); + storage.save(); } /////////////////////////////////////////////////////////////////////////////////////////// - // Setters/Getters + // Getters /////////////////////////////////////////////////////////////////////////////////////////// public List getAcceptedArbitrators() { diff --git a/core/src/main/java/io/bitsquare/user/Preferences.java b/core/src/main/java/io/bitsquare/user/Preferences.java index cdc2548a86..bc589c91cf 100644 --- a/core/src/main/java/io/bitsquare/user/Preferences.java +++ b/core/src/main/java/io/bitsquare/user/Preferences.java @@ -17,7 +17,7 @@ package io.bitsquare.user; -import io.bitsquare.persistence.Persistence; +import io.bitsquare.persistence.Storage; import org.bitcoinj.utils.MonetaryFormat; @@ -33,23 +33,31 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class Preferences implements Serializable { - private static final long serialVersionUID = 7995048077355006861L; + private static final long serialVersionUID = 1L; + transient private static final Logger log = LoggerFactory.getLogger(Preferences.class); - // deactivate mBit for now as most screens are not supporting it yet - private List btcDenominations = Arrays.asList(MonetaryFormat.CODE_BTC/*, MonetaryFormat.CODE_MBTC*/); + // Deactivate mBit for now as most screens are not supporting it yet + transient private static final List BTC_DENOMINATIONS = Arrays.asList(MonetaryFormat.CODE_BTC/*, MonetaryFormat.CODE_MBTC*/); + public static List getBtcDenominations() { + return BTC_DENOMINATIONS; + } - // Needed for persistence as Property objects are transient (not serializable) - // Will be probably removed when we have another persistence solution in place - private String btcDenominationString = MonetaryFormat.CODE_BTC; - private Boolean useAnimationsBoolean = true; - private Boolean useEffectsBoolean = true; + transient private final Storage storage; - final transient StringProperty btcDenomination = new SimpleStringProperty(btcDenominationString); - final transient BooleanProperty useAnimations = new SimpleBooleanProperty(useAnimationsBoolean); - final transient BooleanProperty useEffects = new SimpleBooleanProperty(useEffectsBoolean); - private Persistence persistence; + // Persisted fields + private String _btcDenomination = MonetaryFormat.CODE_BTC; + private Boolean _useAnimations = true; + private Boolean _useEffects = true; + + // Observable wrappers + transient private final StringProperty btcDenomination = new SimpleStringProperty(_btcDenomination); + transient private final BooleanProperty useAnimations = new SimpleBooleanProperty(_useAnimations); + transient private final BooleanProperty useEffects = new SimpleBooleanProperty(_useEffects); /////////////////////////////////////////////////////////////////////////////////////////// @@ -57,105 +65,74 @@ public class Preferences implements Serializable { /////////////////////////////////////////////////////////////////////////////////////////// @Inject - public Preferences(Persistence persistence) { - this.persistence = persistence; + public Preferences(Storage storage) { + this.storage = storage; - applyPersistedSettings(); + Preferences persisted = storage.getPersisted(this); + if (persisted != null) { + setBtcDenomination(persisted._btcDenomination); + setUseAnimations(persisted._useAnimations); + setUseEffects(persisted._useEffects); + } + + // Use that to guarantee update of the serializable field and to make a storage update in case of a change + btcDenomination.addListener((ov) -> { + _btcDenomination = btcDenomination.get(); + storage.save(); + }); + useAnimations.addListener((ov) -> { + _useAnimations = useAnimations.get(); + storage.save(); + }); + useEffects.addListener((ov) -> { + _useEffects = useEffects.get(); + storage.save(); + }); } /////////////////////////////////////////////////////////////////////////////////////////// - // Public API + // Setter /////////////////////////////////////////////////////////////////////////////////////////// - public void applyPersistedSettings() { - Object data = persistence.read(this, "btcDenomination"); - if (data instanceof String) { - btcDenominationString = (String) data; - this.btcDenomination.set(btcDenominationString); - } + public void setBtcDenomination(String btcDenomination) { + this.btcDenomination.set(btcDenomination); + } - data = persistence.read(this, "useEffects"); - if (data instanceof Boolean) { - useEffectsBoolean = (Boolean) data; - this.useEffects.set(useEffectsBoolean); - } + public void setUseAnimations(boolean useAnimations) { + this.useAnimations.set(useAnimations); + } - data = persistence.read(this, "useAnimations"); - if (data instanceof Boolean) { - useAnimationsBoolean = (Boolean) data; - this.useAnimations.set(useAnimationsBoolean); - } + public void setUseEffects(boolean useEffects) { + this.useEffects.set(useEffects); } /////////////////////////////////////////////////////////////////////////////////////////// - // Setters/Getters + // Getter /////////////////////////////////////////////////////////////////////////////////////////// - public List getBtcDenominations() { - return btcDenominations; - } - - // btcDenomination public String getBtcDenomination() { return btcDenomination.get(); } + public boolean getUseEffects() { + return useEffects.get(); + } + + public boolean getUseAnimations() { + return useAnimations.get(); + } + public StringProperty btcDenominationProperty() { return btcDenomination; } - public void setBtcDenomination(String btcDenomination) { - persistence.write(this, "btcDenomination", btcDenomination); - btcDenominationString = btcDenomination; - this.btcDenomination.set(btcDenomination); - } - - // for persistence - public String getBtcDenominationString() { - return btcDenominationString; - } - - - // useAnimations - public boolean getUseAnimations() { - return useAnimations.get(); - } - public BooleanProperty useAnimationsProperty() { return useAnimations; } - public void setUseAnimations(boolean useAnimations) { - persistence.write(this, "useAnimations", useAnimations); - useAnimationsBoolean = useAnimations; - this.useAnimations.set(useAnimations); - } - - // for persistence - public boolean getUseAnimationsBooleanBoolean() { - return useAnimationsBoolean; - } - - // useEffects - public boolean getUseEffects() { - return useEffects.get(); - } - public BooleanProperty useEffectsProperty() { return useEffects; } - - public void setUseEffects(boolean useEffects) { - persistence.write(this, "useEffects", useEffects); - useEffectsBoolean = useEffects; - this.useEffects.set(useEffects); - } - - // for persistence - public boolean getUseEffectsBoolean() { - return useEffectsBoolean; - } - } diff --git a/core/src/main/java/io/bitsquare/user/User.java b/core/src/main/java/io/bitsquare/user/User.java index 40f683a6fa..9d96e9c10c 100644 --- a/core/src/main/java/io/bitsquare/user/User.java +++ b/core/src/main/java/io/bitsquare/user/User.java @@ -19,7 +19,8 @@ package io.bitsquare.user; import io.bitsquare.crypto.EncryptionService; import io.bitsquare.fiat.FiatAccount; -import io.bitsquare.util.DSAKeyUtil; +import io.bitsquare.gui.components.Popups; +import io.bitsquare.persistence.Storage; import java.io.Serializable; @@ -49,78 +50,95 @@ import org.slf4j.LoggerFactory; * It must never be transmitted over the wire (messageKeyPair contains private key!). */ public class User implements Serializable { - private static final long serialVersionUID = 7409078808248518638L; - private static final Logger log = LoggerFactory.getLogger(User.class); + private static final long serialVersionUID = 1L; + transient private static final Logger log = LoggerFactory.getLogger(User.class); + transient private Storage storage; + transient private EncryptionService encryptionService; + + // Persisted fields private KeyPair p2pSigKeyPair; private KeyPair p2pEncryptKeyPair; private String accountID; - - // Used for serialisation (ObservableList cannot be serialized) -> serialisation will change anyway so that is - // only temporary private List _fiatAccounts = new ArrayList<>(); private FiatAccount _currentFiatAccount; - private final transient ObservableList fiatAccounts = FXCollections.observableArrayList(); - private final transient ObjectProperty currentBankAccount = new SimpleObjectProperty<>(); - transient private EncryptionService encryptionService; + // Observable wrappers + transient private final ObservableList fiatAccounts = FXCollections.observableArrayList(); + transient private final ObjectProperty currentFiatAccount = new SimpleObjectProperty<>(); @Inject - public User(EncryptionService encryptionService) { + public User(Storage storage, EncryptionService encryptionService) { + this.storage = storage; this.encryptionService = encryptionService; - // Used for serialisation (ObservableList cannot be serialized) -> serialisation will change anyway so that is - // only temporary - fiatAccounts.addListener((ListChangeListener) change -> _fiatAccounts = new ArrayList<>(fiatAccounts)); - currentBankAccount.addListener((ov) -> _currentFiatAccount = currentBankAccount.get()); + User persisted = storage.getPersisted(this); + if (persisted != null) { + p2pSigKeyPair = persisted.getP2pSigKeyPair(); + p2pEncryptKeyPair = persisted.getP2pEncryptKeyPair(); + accountID = persisted.getAccountId(); + + _fiatAccounts = new ArrayList<>(persisted.getFiatAccounts()); + fiatAccounts.setAll(_fiatAccounts); + + _currentFiatAccount = persisted.getCurrentFiatAccount(); + currentFiatAccount.set(_currentFiatAccount); + } + else { + // First time we create key pairs + try { + p2pSigKeyPair = encryptionService.getGeneratedDSAKeyPair(); + p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + log.error(e.getMessage()); + Popups.openExceptionPopup(e); + } + } + storage.save(); + // Use that to guarantee update of the serializable field and to make a storage update in case of a change + fiatAccounts.addListener((ListChangeListener) change -> { + _fiatAccounts = new ArrayList<>(fiatAccounts); + storage.save(); + }); + currentFiatAccount.addListener((ov) -> { + _currentFiatAccount = currentFiatAccount.get(); + storage.save(); + }); } // for unit tests public User() { } + /////////////////////////////////////////////////////////////////////////////////////////// // Public Methods /////////////////////////////////////////////////////////////////////////////////////////// - public void applyPersistedUser(User persistedUser) { - if (persistedUser != null) { - fiatAccounts.setAll(persistedUser.getSerializedBankAccounts()); - setCurrentBankAccount(persistedUser.getSerializedCurrentBankAccount()); - p2pSigKeyPair = persistedUser.getP2pSigKeyPair(); - p2pEncryptKeyPair = persistedUser.getP2pEncryptKeyPair(); - accountID = persistedUser.getAccountId(); - } - else { - // First time - p2pSigKeyPair = DSAKeyUtil.generateDSAKeyPair(); - try { - p2pEncryptKeyPair = encryptionService.getKeyPair(); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - log.error(e.getMessage()); - } - } - } - - public void setBankAccount(FiatAccount fiatAccount) { - // We use the account title as hashCode - // In case we edit an existing we replace it in the list + /** + * @param fiatAccount + * @return If a Fiat Account with the same name already exists we return false. We use the account title as hashCode. + */ + public boolean addFiatAccount(FiatAccount fiatAccount) { if (fiatAccounts.contains(fiatAccount)) - fiatAccounts.remove(fiatAccount); + return false; fiatAccounts.add(fiatAccount); - setCurrentBankAccount(fiatAccount); + setCurrentFiatAccount(fiatAccount); + return true; } - public void removeCurrentBankAccount() { - if (currentBankAccount.get() != null) - fiatAccounts.remove(currentBankAccount.get()); + // In case we edit an existing we remove the existing first + public void removeFiatAccount(FiatAccount fiatAccount) { + fiatAccounts.remove(fiatAccount); - if (fiatAccounts.isEmpty()) - setCurrentBankAccount(null); - else - setCurrentBankAccount(fiatAccounts.get(0)); + if (_currentFiatAccount.equals(fiatAccount)) { + if (fiatAccounts.isEmpty()) + setCurrentFiatAccount(null); + else + setCurrentFiatAccount(fiatAccounts.get(0)); + } } @@ -132,19 +150,20 @@ public class User implements Serializable { // Public key from the input for the registration payment tx (or address) will be used public void setAccountID(String accountID) { this.accountID = accountID; + storage.save(); } - public void setCurrentBankAccount(@Nullable FiatAccount fiatAccount) { - currentBankAccount.set(fiatAccount); + public void setCurrentFiatAccount(@Nullable FiatAccount fiatAccount) { + currentFiatAccount.set(fiatAccount); } + /////////////////////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////////////////////// // TODO just a first attempt, refine when working on the embedded data for the reg. tx public String getStringifiedBankAccounts() { - // TODO use steam API String bankAccountUIDs = ""; for (int i = 0; i < fiatAccounts.size(); i++) { FiatAccount fiatAccount = fiatAccounts.get(i); @@ -165,17 +184,9 @@ public class User implements Serializable { return getAccountId() != null; } - public ObservableList getFiatAccounts() { - return fiatAccounts; - } - - public ObjectProperty getCurrentBankAccount() { - return currentBankAccount; - } - - public FiatAccount getBankAccount(String bankAccountId) { - for (final FiatAccount fiatAccount : fiatAccounts) { - if (fiatAccount.getUid().equals(bankAccountId)) { + public FiatAccount getFiatAccount(String fiatAccountId) { + for (FiatAccount fiatAccount : fiatAccounts) { + if (fiatAccount.getId().equals(fiatAccountId)) { return fiatAccount; } } @@ -194,24 +205,28 @@ public class User implements Serializable { return p2pEncryptKeyPair.getPublic(); } - public ObjectProperty currentBankAccountProperty() { - return currentBankAccount; - } - - // Used for serialisation (ObservableList cannot be serialized) - List getSerializedBankAccounts() { - return _fiatAccounts; - } - - FiatAccount getSerializedCurrentBankAccount() { - return _currentFiatAccount; - } - public PrivateKey getP2pEncryptPrivateKey() { return p2pEncryptKeyPair.getPrivate(); } - KeyPair getP2pEncryptKeyPair() { + private KeyPair getP2pEncryptKeyPair() { return p2pEncryptKeyPair; } + + private List getFiatAccounts() { + return _fiatAccounts; + } + + private FiatAccount getCurrentFiatAccount() { + return _currentFiatAccount; + } + + public ObjectProperty currentFiatAccountProperty() { + return currentFiatAccount; + } + + public ObservableList fiatAccountsObservableList() { + return fiatAccounts; + } + } diff --git a/core/src/main/java/io/bitsquare/util/DSAKeyUtil.java b/core/src/main/java/io/bitsquare/util/DSAKeyUtil.java deleted file mode 100755 index 70d9464216..0000000000 --- a/core/src/main/java/io/bitsquare/util/DSAKeyUtil.java +++ /dev/null @@ -1,49 +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 . - */ - -package io.bitsquare.util; - -import org.bitcoinj.core.Utils; - -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.spec.X509EncodedKeySpec; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DSAKeyUtil { - private static final Logger log = LoggerFactory.getLogger(DSAKeyUtil.class); - - public static String getHexStringFromPublicKey(PublicKey publicKey) { - final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded()); - return Utils.HEX.encode(x509EncodedKeySpec.getEncoded()); - } - - public static KeyPair generateDSAKeyPair() { - try { - final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); - keyGen.initialize(1024); - return keyGen.genKeyPair(); - } catch (NoSuchAlgorithmException e) { - log.error(e.toString()); - } - return null; - } -} diff --git a/core/src/main/java/io/bitsquare/util/FileUtil.java b/core/src/main/java/io/bitsquare/util/FileUtil.java new file mode 100644 index 0000000000..2771db064b --- /dev/null +++ b/core/src/main/java/io/bitsquare/util/FileUtil.java @@ -0,0 +1,120 @@ +/* + * 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 . + */ + +package io.bitsquare.util; + +import org.bitcoinj.core.Utils; +import org.bitcoinj.utils.Threading; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import java.util.concurrent.locks.ReentrantLock; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FileUtil { + private static final Logger log = LoggerFactory.getLogger(FileUtil.class); + private static final ReentrantLock lock = Threading.lock("FileUtil"); + + public static void write(Serializable serializable, File dir, File storageFile) throws IOException { + lock.lock(); + File tempFile = null; + FileOutputStream fileOutputStream = null; + ObjectOutputStream objectOutputStream = null; + try { + if (!dir.exists()) + dir.mkdir(); + + tempFile = File.createTempFile("temp", null, dir); + + // Don't use auto closeable resources in try() as we would need too many try/catch clauses (for tempFile) + // and we need to close it + // manually before replacing file with temp file + fileOutputStream = new FileOutputStream(tempFile); + objectOutputStream = new ObjectOutputStream(fileOutputStream); + + objectOutputStream.writeObject(serializable); + + // Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide + // to not write through to physical media for at least a few seconds, but this is the best we can do. + fileOutputStream.flush(); + fileOutputStream.getFD().sync(); + + // Close resources before replacing file with temp file because otherwise it causes problems on windows + // when rename temp file + fileOutputStream.close(); + objectOutputStream.close(); + + writeTempFileToFile(tempFile, storageFile); + } finally { + if (tempFile != null && tempFile.exists()) { + log.warn("Temp file still exists after failed save."); + if (!tempFile.delete()) log.error("Cannot delete temp file."); + } + + try { + if (objectOutputStream != null) + objectOutputStream.close(); + if (fileOutputStream != null) + fileOutputStream.close(); + } catch (IOException e) { + // We swallow that + e.printStackTrace(); + log.error("Cannot close resources."); + } + lock.unlock(); + } + } + + public static Object read(File file) throws IOException, ClassNotFoundException { + lock.lock(); + try (final FileInputStream fileInputStream = new FileInputStream(file); + final ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) { + return objectInputStream.readObject(); + } finally { + lock.unlock(); + } + } + + private static void writeTempFileToFile(File tempFile, File file) throws IOException { + lock.lock(); + try { + if (Utils.isWindows()) { + // Work around an issue on Windows whereby you can't rename over existing files. + final File canonical = file.getCanonicalFile(); + if (canonical.exists() && !canonical.delete()) { + throw new IOException("Failed to delete canonical file for replacement with save"); + } + if (!tempFile.renameTo(canonical)) { + throw new IOException("Failed to rename " + tempFile + " to " + canonical); + } + } + else if (!tempFile.renameTo(file)) { + throw new IOException("Failed to rename " + tempFile + " to " + file); + } + } finally { + lock.unlock(); + } + } +} diff --git a/core/src/main/java/io/bitsquare/util/Utilities.java b/core/src/main/java/io/bitsquare/util/Utilities.java index c4fc8e8c2b..ab9b31e3cf 100644 --- a/core/src/main/java/io/bitsquare/util/Utilities.java +++ b/core/src/main/java/io/bitsquare/util/Utilities.java @@ -17,6 +17,8 @@ package io.bitsquare.util; +import org.bitcoinj.core.Utils; + import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -35,6 +37,9 @@ import java.io.Serializable; import java.net.URI; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; + import java.util.function.Function; import javafx.animation.AnimationTimer; @@ -289,4 +294,9 @@ public class Utilities { animationTimer.start(); return animationTimer; } + + public static String getHexStringFromPublicKey(PublicKey publicKey) { + final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded()); + return Utils.HEX.encode(x509EncodedKeySpec.getEncoded()); + } } diff --git a/core/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java b/core/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java index f6c20b6c71..542cc66eb0 100644 --- a/core/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java +++ b/core/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java @@ -36,7 +36,7 @@ public class EncryptionServiceTests { @Test public void testEncryptionWithMailboxMessage() throws Exception { EncryptionService encryptionService = new EncryptionService<>(); - KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair(); + KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair(); TestMessage message = new TestMessage("test"); EncryptionPackage encryptionPackage = encryptionService.encryptObject(p2pEncryptKeyPair.getPublic(), message); @@ -47,7 +47,7 @@ public class EncryptionServiceTests { @Test public void testEncryptionWithInteger() throws Exception { EncryptionService encryptionService = new EncryptionService<>(); - KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair(); + KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair(); int data = 1234; EncryptionPackage encryptionPackage = encryptionService.encryptObject(p2pEncryptKeyPair.getPublic(), data); Integer result = encryptionService.decryptToObject(p2pEncryptKeyPair.getPrivate(), encryptionPackage); @@ -57,7 +57,7 @@ public class EncryptionServiceTests { @Test public void testEncryptionWithBytes() throws Exception { EncryptionService encryptionService = new EncryptionService(); - KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair(); + KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair(); byte[] data = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04}; EncryptionPackage encryptionPackage = encryptionService.encrypt(p2pEncryptKeyPair.getPublic(), data); @@ -68,7 +68,7 @@ public class EncryptionServiceTests { @Test public void testEncryptionWithLargeData() throws Exception { EncryptionService encryptionService = new EncryptionService(); - KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair(); + KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair(); byte[] data = new byte[2000]; new Random().nextBytes(data); diff --git a/core/src/test/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocolTest.java b/core/src/test/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocolTest.java index 3efd4654bb..50ce2f5472 100644 --- a/core/src/test/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocolTest.java +++ b/core/src/test/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocolTest.java @@ -18,26 +18,26 @@ package io.bitsquare.trade.protocol.placeoffer; import io.bitsquare.arbitration.Arbitrator; -import io.bitsquare.fiat.FiatAccountType; import io.bitsquare.btc.BitcoinNetwork; import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.UserAgent; import io.bitsquare.btc.WalletService; +import io.bitsquare.crypto.EncryptionService; +import io.bitsquare.fiat.FiatAccountType; import io.bitsquare.locale.CountryUtil; import io.bitsquare.locale.LanguageUtil; -import io.bitsquare.p2p.BootstrapState; -import io.bitsquare.p2p.Node; -import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder; -import io.bitsquare.p2p.tomp2p.TomP2PNode; import io.bitsquare.offer.Direction; import io.bitsquare.offer.Offer; import io.bitsquare.offer.OfferBookService; import io.bitsquare.offer.tomp2p.TomP2POfferBookService; -import io.bitsquare.persistence.Persistence; +import io.bitsquare.p2p.BootstrapState; import io.bitsquare.p2p.MessageService; +import io.bitsquare.p2p.Node; +import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder; import io.bitsquare.p2p.tomp2p.TomP2PMessageService; +import io.bitsquare.p2p.tomp2p.TomP2PNode; +import io.bitsquare.persistence.Persistence; import io.bitsquare.user.User; -import io.bitsquare.util.DSAKeyUtil; import org.bitcoinj.core.Address; import org.bitcoinj.core.Coin; @@ -46,6 +46,8 @@ import org.bitcoinj.utils.Threading; import java.io.File; import java.io.IOException; +import java.security.NoSuchAlgorithmException; + import java.util.Arrays; import java.util.Currency; import java.util.concurrent.CountDownLatch; @@ -93,7 +95,11 @@ public class PlaceOfferProtocolTest { // messageService Node bootstrapNode = Node.at("localhost", "127.0.0.1"); User user = new User(); - user.applyPersistedUser(null); + /* try { + user.initPersistedObject(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + }*/ bootstrappedPeerBuilder = new BootstrappedPeerBuilder(Node.DEFAULT_PORT, false, bootstrapNode, ""); tomP2PNode = new TomP2PNode(bootstrappedPeerBuilder); messageService = new TomP2PMessageService(tomP2PNode, null, null, null); @@ -119,6 +125,7 @@ public class PlaceOfferProtocolTest { new FeePolicy(BitcoinNetwork.REGTEST), null, persistence, + null, new UserAgent("", ""), dir, "Tests" @@ -294,9 +301,9 @@ public class PlaceOfferProtocolTest { faultHandler); }*/ - private Offer getOffer() { + private Offer getOffer() throws NoSuchAlgorithmException { return new Offer(OFFER_ID, - DSAKeyUtil.generateDSAKeyPair().getPublic(), + new EncryptionService().getGeneratedDSAKeyPair().getPublic(), Direction.BUY, 100L, Coin.CENT, diff --git a/pom.xml b/pom.xml index 56bb101a04..33927ec62e 100755 --- a/pom.xml +++ b/pom.xml @@ -93,23 +93,6 @@ - - org.bitcoinj - bitcoinj-core - 0.13.d13665c-SNAPSHOT - - - - - com.google.guava - guava - 16.0.1 - - junit junit