Skip to content

Commit

Permalink
Extract parsing functions from BSFormatter to ParsingUtils
Browse files Browse the repository at this point in the history
Parsing and formatting are 2 different concerns, its better to have 2
classes that handle these.
  • Loading branch information
Justin Carter committed Sep 11, 2019
1 parent fe33a80 commit 3b46f35
Show file tree
Hide file tree
Showing 23 changed files with 164 additions and 136 deletions.
4 changes: 2 additions & 2 deletions core/src/main/java/bisq/core/dao/state/DaoStateService.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
import bisq.core.dao.state.model.governance.Issuance;
import bisq.core.dao.state.model.governance.IssuanceType;
import bisq.core.dao.state.model.governance.ParamChange;
import bisq.core.util.BSFormatter;
import bisq.core.util.BsqFormatter;
import bisq.core.util.ParsingUtils;

import org.bitcoinj.core.Coin;

Expand Down Expand Up @@ -924,7 +924,7 @@ public Coin getParamValueAsCoin(Param param, String paramValue) {
}

public double getParamValueAsPercentDouble(String paramValue) {
return BSFormatter.parsePercentStringToDouble(paramValue);
return ParsingUtils.parsePercentStringToDouble(paramValue);
}

public int getParamValueAsBlock(String paramValue) {
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/bisq/core/monetary/Altcoin.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

package bisq.core.monetary;

import bisq.core.util.BSFormatter;
import bisq.core.util.ParsingUtils;

import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.MonetaryFormat;
Expand Down Expand Up @@ -89,7 +89,7 @@ public String getCurrencyCode() {
* @throws IllegalArgumentException if you try to specify fractional satoshis, or a value out of range.
*/
public static Altcoin parseAltcoin(final String currencyCode, String input) {
String cleaned = BSFormatter.convertCharsForNumber(input);
String cleaned = ParsingUtils.convertCharsForNumber(input);
try {
long val = new BigDecimal(cleaned).movePointRight(SMALLEST_UNIT_EXPONENT)
.toBigIntegerExact().longValue();
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/bisq/core/monetary/Price.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
package bisq.core.monetary;

import bisq.core.locale.CurrencyUtil;
import bisq.core.util.BSFormatter;
import bisq.core.util.ParsingUtils;

import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Monetary;
Expand Down Expand Up @@ -58,7 +58,7 @@ public Price(Monetary monetary) {
* @return The parsed Price.
*/
public static Price parse(String currencyCode, String input) {
String cleaned = BSFormatter.convertCharsForNumber(input);
String cleaned = ParsingUtils.convertCharsForNumber(input);
if (CurrencyUtil.isFiatCurrency(currencyCode))
return new Price(Fiat.parseFiat(currencyCode, cleaned));
else
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/bisq/core/monetary/Volume.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
package bisq.core.monetary;

import bisq.core.locale.CurrencyUtil;
import bisq.core.util.BSFormatter;
import bisq.core.util.ParsingUtils;

import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.Fiat;
Expand All @@ -36,7 +36,7 @@ public Volume(Monetary monetary) {
}

public static Volume parse(String input, String currencyCode) {
String cleaned = BSFormatter.convertCharsForNumber(input);
String cleaned = ParsingUtils.convertCharsForNumber(input);
if (CurrencyUtil.isFiatCurrency(currencyCode))
return new Volume(Fiat.parseFiat(currencyCode, cleaned));
else
Expand Down
90 changes: 10 additions & 80 deletions core/src/main/java/bisq/core/util/BSFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import java.util.TimeZone;
import java.util.stream.Collectors;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import org.jetbrains.annotations.NotNull;
Expand All @@ -66,7 +67,8 @@ public class BSFormatter {
// Input of a group separator (1,123,45) lead to an validation error.
// Note: BtcFormat was intended to be used, but it lead to many problems (automatic format to mBit,
// no way to remove grouping separator). It seems to be not optimal for user input formatting.
protected MonetaryFormat coinFormat;
@Getter
protected MonetaryFormat monetaryFormat;

// protected String currencyCode = CurrencyUtil.getDefaultFiatCurrencyAsCode();

Expand All @@ -77,7 +79,7 @@ public class BSFormatter {

@Inject
public BSFormatter() {
coinFormat = BisqEnvironment.getParameters().getMonetaryFormat();
monetaryFormat = BisqEnvironment.getParameters().getMonetaryFormat();
}


Expand All @@ -99,7 +101,7 @@ public String formatCoin(long value, MonetaryFormat coinFormat) {
}

public String formatCoin(Coin coin, int decimalPlaces, boolean decimalAligned, int maxNumberOfDigits) {
return formatCoin(coin, decimalPlaces, decimalAligned, maxNumberOfDigits, coinFormat);
return formatCoin(coin, decimalPlaces, decimalAligned, maxNumberOfDigits, monetaryFormat);
}

public static String formatCoin(Coin coin,
Expand Down Expand Up @@ -129,11 +131,11 @@ public static String formatCoin(Coin coin,
}

public String formatCoinWithCode(Coin coin) {
return formatCoinWithCode(coin, coinFormat);
return formatCoinWithCode(coin, monetaryFormat);
}

public String formatCoinWithCode(long value) {
return formatCoinWithCode(Coin.valueOf(value), coinFormat);
return formatCoinWithCode(Coin.valueOf(value), monetaryFormat);
}

public static String formatCoinWithCode(long value, MonetaryFormat coinFormat) {
Expand All @@ -155,24 +157,6 @@ public static String formatCoinWithCode(Coin coin, MonetaryFormat coinFormat) {
}
}

public Coin parseToCoin(String input) {
return parseToCoin(input, coinFormat);
}

public Coin parseToCoin(String input, MonetaryFormat coinFormat) {
if (input != null && input.length() > 0) {
try {
return coinFormat.parse(cleanDoubleInput(input));
} catch (Throwable t) {
log.warn("Exception at parseToBtc: " + t.toString());
return Coin.ZERO;
}
} else {
return Coin.ZERO;
}
}


///////////////////////////////////////////////////////////////////////////////////////////
// FIAT
///////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -194,10 +178,10 @@ public static String formatFiat(Fiat fiat, MonetaryFormat format, boolean append
}
}

protected static Fiat parseToFiat(String input, String currencyCode) {
private static Fiat parseToFiat(String input, String currencyCode) {
if (input != null && input.length() > 0) {
try {
return Fiat.parseFiat(currencyCode, cleanDoubleInput(input));
return Fiat.parseFiat(currencyCode, ParsingUtils.cleanDoubleInput(input));
} catch (Exception e) {
log.warn("Exception at parseToFiat: " + e.toString());
return Fiat.valueOf(currencyCode, 0);
Expand All @@ -220,7 +204,7 @@ protected static Fiat parseToFiat(String input, String currencyCode) {
public static Fiat parseToFiatWithPrecision(String input, String currencyCode) {
if (input != null && input.length() > 0) {
try {
return parseToFiat(new BigDecimal(cleanDoubleInput(input)).setScale(2, BigDecimal.ROUND_HALF_UP).toString(),
return parseToFiat(new BigDecimal(ParsingUtils.cleanDoubleInput(input)).setScale(2, BigDecimal.ROUND_HALF_UP).toString(),
currencyCode);
} catch (Throwable t) {
log.warn("Exception at parseToFiatWithPrecision: " + t.toString());
Expand Down Expand Up @@ -387,60 +371,6 @@ public static String formatToPercent(double value) {
return decimalFormat.format(MathUtils.roundDouble(value * 100.0, 2)).replace(",", ".");
}

public static double parseNumberStringToDouble(String input) throws NumberFormatException {
return Double.parseDouble(cleanDoubleInput(input));
}

public static double parsePercentStringToDouble(String percentString) throws NumberFormatException {
String input = percentString.replace("%", "");
input = cleanDoubleInput(input);
double value = Double.parseDouble(input);
return MathUtils.roundDouble(value / 100d, 4);
}

public static long parsePriceStringToLong(BSFormatter bsFormatter,
String currencyCode,
String amount,
int precision) {
if (amount == null || amount.isEmpty())
return 0;

long value = 0;
try {
double amountValue = Double.parseDouble(amount);
amount = BSFormatter.formatRoundedDoubleWithPrecision(amountValue, precision);
value = Price.parse(currencyCode, amount).getValue();
} catch (NumberFormatException ignore) {
// expected NumberFormatException if input is not a number
} catch (Throwable t) {
log.error("parsePriceStringToLong: " + t.toString());
}

return value;
}

public static String convertCharsForNumber(String input) {
// Some languages like finnish use the long dash for the minus
input = input.replace("−", "-");
input = StringUtils.deleteWhitespace(input);
return input.replace(",", ".");
}

public static String cleanDoubleInput(String input) {
input = convertCharsForNumber(input);
if (input.equals("."))
input = input.replace(".", "0.");
if (input.equals("-."))
input = input.replace("-.", "-0.");
// don't use String.valueOf(Double.parseDouble(input)) as return value as it gives scientific
// notation (1.0E-6) which screw up coinFormat.parse
//noinspection ResultOfMethodCallIgnored
// Just called to check if we have a valid double, throws exception otherwise
//noinspection ResultOfMethodCallIgnored
Double.parseDouble(input);
return input;
}

public static String formatDurationAsWords(long durationMillis) {
return formatDurationAsWords(durationMillis, false, true);
}
Expand Down
22 changes: 11 additions & 11 deletions core/src/main/java/bisq/core/util/BsqFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ public BsqFormatter() {
GlobalSettings.localeProperty().addListener((observable, oldValue, newValue) -> setFormatter(newValue));
setFormatter(GlobalSettings.getLocale());

btcCoinFormat = super.coinFormat;
btcCoinFormat = super.monetaryFormat;

final String baseCurrencyCode = BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode();
switch (baseCurrencyCode) {
case "BTC":
coinFormat = new MonetaryFormat().shift(6).code(6, "BSQ").minDecimals(2);
monetaryFormat = new MonetaryFormat().shift(6).code(6, "BSQ").minDecimals(2);
break;
default:
throw new RuntimeException("baseCurrencyCode not defined. baseCurrencyCode=" + baseCurrencyCode);
Expand Down Expand Up @@ -123,11 +123,11 @@ public String formatMarketCap(MarketPrice bsqPriceMarketPrice, MarketPrice fiatM
}

public String formatBSQSatoshis(long satoshi) {
return super.formatCoin(satoshi, coinFormat);
return super.formatCoin(satoshi, monetaryFormat);
}

public String formatBSQSatoshisWithCode(long satoshi) {
return super.formatCoinWithCode(satoshi, coinFormat);
return super.formatCoinWithCode(satoshi, monetaryFormat);
}

public String formatBTCSatoshis(long satoshi) {
Expand All @@ -147,20 +147,20 @@ public String formatBTC(Coin coin) {
}

public Coin parseToBTC(String input) {
return super.parseToCoin(input, btcCoinFormat);
return ParsingUtils.parseToCoin(input, btcCoinFormat);
}

public void validateBtcInput(String input) throws ProposalValidationException {
validateCoinInput(input, btcCoinFormat);
}

public void validateBsqInput(String input) throws ProposalValidationException {
validateCoinInput(input, this.coinFormat);
validateCoinInput(input, this.monetaryFormat);
}

private void validateCoinInput(String input, MonetaryFormat coinFormat) throws ProposalValidationException {
try {
coinFormat.parse(cleanDoubleInput(input));
coinFormat.parse(ParsingUtils.cleanDoubleInput(input));
} catch (Throwable t) {
throw new ProposalValidationException("Invalid format for a " + coinFormat.code() + " value");
}
Expand All @@ -172,11 +172,11 @@ public String formatParamValue(Param param, String value) {
// In case we add a new param old clients will not know that enum and fall back to UNDEFINED.
return Res.get("shared.na");
case BSQ:
return formatCoinWithCode(parseToCoin(value));
return formatCoinWithCode(ParsingUtils.parseToCoin(value, this));
case BTC:
return formatBTCWithCode(parseToBTC(value));
case PERCENT:
return formatToPercentWithSymbol(parsePercentStringToDouble(value));
return formatToPercentWithSymbol(ParsingUtils.parsePercentStringToDouble(value));
case BLOCK:
return Res.get("dao.param.blocks", Integer.parseInt(value));
case ADDRESS:
Expand All @@ -190,7 +190,7 @@ public String formatParamValue(Param param, String value) {
public Coin parseParamValueToCoin(Param param, String inputValue) {
switch (param.getParamType()) {
case BSQ:
return parseToCoin(inputValue);
return ParsingUtils.parseToCoin(inputValue, this);
case BTC:
return parseToBTC(inputValue);
default:
Expand All @@ -216,7 +216,7 @@ public String parseParamValueToString(Param param, String inputValue) throws Pro
case BTC:
return formatBTC(parseParamValueToCoin(param, inputValue));
case PERCENT:
return formatToPercent(parsePercentStringToDouble(inputValue));
return formatToPercent(ParsingUtils.parsePercentStringToDouble(inputValue));
case BLOCK:
return Integer.toString(parseParamValueToBlocks(param, inputValue));
case ADDRESS:
Expand Down
83 changes: 83 additions & 0 deletions core/src/main/java/bisq/core/util/ParsingUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package bisq.core.util;

import bisq.core.monetary.Price;

import bisq.common.util.MathUtils;

import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.MonetaryFormat;

import org.apache.commons.lang3.StringUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ParsingUtils {
public static Coin parseToCoin(String input, BSFormatter bsFormatter) {
return parseToCoin(input, bsFormatter.getMonetaryFormat());
}

public static Coin parseToCoin(String input, MonetaryFormat coinFormat) {
if (input != null && input.length() > 0) {
try {
return coinFormat.parse(cleanDoubleInput(input));
} catch (Throwable t) {
log.warn("Exception at parseToBtc: " + t.toString());
return Coin.ZERO;
}
} else {
return Coin.ZERO;
}
}

public static double parseNumberStringToDouble(String input) throws NumberFormatException {
return Double.parseDouble(cleanDoubleInput(input));
}

public static double parsePercentStringToDouble(String percentString) throws NumberFormatException {
String input = percentString.replace("%", "");
input = cleanDoubleInput(input);
double value = Double.parseDouble(input);
return MathUtils.roundDouble(value / 100d, 4);
}

public static long parsePriceStringToLong(String currencyCode, String amount, int precision) {
if (amount == null || amount.isEmpty())
return 0;

long value = 0;
try {
double amountValue = Double.parseDouble(amount);
amount = BSFormatter.formatRoundedDoubleWithPrecision(amountValue, precision);
value = Price.parse(currencyCode, amount).getValue();
} catch (NumberFormatException ignore) {
// expected NumberFormatException if input is not a number
} catch (Throwable t) {
log.error("parsePriceStringToLong: " + t.toString());
}

return value;
}

public static String convertCharsForNumber(String input) {
// Some languages like finnish use the long dash for the minus
input = input.replace("−", "-");
input = StringUtils.deleteWhitespace(input);
return input.replace(",", ".");
}

public static String cleanDoubleInput(String input) {
input = convertCharsForNumber(input);
if (input.equals("."))
input = input.replace(".", "0.");
if (input.equals("-."))
input = input.replace("-.", "-0.");
// don't use String.valueOf(Double.parseDouble(input)) as return value as it gives scientific
// notation (1.0E-6) which screw up coinFormat.parse
//noinspection ResultOfMethodCallIgnored
// Just called to check if we have a valid double, throws exception otherwise
//noinspection ResultOfMethodCallIgnored
Double.parseDouble(input);
return input;
}
}
Loading

0 comments on commit 3b46f35

Please sign in to comment.