Merge pull request #1449 from cbeams/isolate-desktop

Isolate 'gui' module and rename to 'bisq-desktop'
This commit is contained in:
Chris Beams 2018-03-10 19:01:12 +01:00
commit 83a6e74a5a
No known key found for this signature in database
GPG Key ID: 3D214F8F5BC5ED73
1449 changed files with 393 additions and 85039 deletions

1
.gitignore vendored
View File

@ -27,4 +27,3 @@ build
desktop.ini
*/target/*
*.class
/gui/deploy/*

View File

@ -1,7 +0,0 @@
# This file determines which @bisq-network/exchange-maintainers get suggested
# to review each pull request submitted to this repository. For more details,
# see https://help.github.com/articles/about-codeowners/.
* @ManfredKarrer
/gui/* @ripcurlx

View File

@ -1,173 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>io.bisq.exchange</groupId>
<version>-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common</artifactId>
<properties>
<protobuf.version>3.3.0</protobuf.version>
</properties>
<profiles>
<profile>
<id>windows</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<properties>
<protobuf.classifier>windows-x86_64</protobuf.classifier>
<protobuf.exe>protoc.exe</protobuf.exe>
</properties>
</profile>
<profile>
<id>unix</id>
<activation>
<os>
<family>unix</family>
<name>Linux</name>
</os>
</activation>
<properties>
<protobuf.classifier>linux-x86_64</protobuf.classifier>
<protobuf.exe>protoc</protobuf.exe>
</properties>
</profile>
<profile>
<id>macos</id>
<activation>
<os>
<family>mac</family>
</os>
</activation>
<properties>
<protobuf.classifier>osx-x86_64</protobuf.classifier>
<protobuf.exe>protoc</protobuf.exe>
</properties>
</profile>
</profiles>
<build>
<plugins>
<!-- unpack correct protobuf exe for current os -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-protoc</id>
<phase>generate-sources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.google.protobuf</groupId>
<artifactId>protoc</artifactId>
<version>${protobuf.version}</version>
<classifier>${protobuf.classifier}</classifier>
<type>exe</type>
<overWrite>true</overWrite>
<destFileName>${protobuf.exe}</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>set-permissions</id>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<chmod file="${project.build.directory}/dependency/${protobuf.exe}" perm="u+rx"/>
<echo message="permissions changed for ${project.build.directory}/dependency/${protobuf.exe}"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
<!-- Run protobuf https://www.xolstice.org/protobuf-maven-plugin/usage.html -->
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<configuration>
<protocExecutable>${project.build.directory}/dependency/${protobuf.exe}</protocExecutable>
</configuration>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<!-- Only used for the JsonFormat class, can otherwise be put in scope 'test' -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>${protobuf.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.7</version>
</dependency>
<!-- used only for reading json file for trade statistic migration
can be removed later -->
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,67 +0,0 @@
package io.bisq.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
// Helps configure listener objects that are run by the `UserThread` each second
// and can do per second, per minute and delayed second actions.
public class Clock {
private static final Logger log = LoggerFactory.getLogger(Clock.class);
public static final int IDLE_TOLERANCE = 20000;
public interface Listener {
void onSecondTick();
void onMinuteTick();
void onMissedSecondTick(long missed);
}
private Timer timer;
private final List<Listener> listeners = new LinkedList<>();
private long counter = 0;
private long lastSecondTick;
public Clock() {
}
public void start() {
if (timer == null) {
lastSecondTick = System.currentTimeMillis();
timer = UserThread.runPeriodically(() -> {
listeners.stream().forEach(Listener::onSecondTick);
counter++;
if (counter >= 60) {
counter = 0;
listeners.stream().forEach(Listener::onMinuteTick);
}
long currentTimeMillis = System.currentTimeMillis();
long diff = currentTimeMillis - lastSecondTick;
if (diff > 1000)
listeners.stream().forEach(listener -> listener.onMissedSecondTick(diff - 1000));
lastSecondTick = currentTimeMillis;
}, 1, TimeUnit.SECONDS);
}
}
public void stop() {
timer.stop();
timer = null;
counter = 0;
}
public void addListener(Listener listener) {
listeners.add(listener);
}
public void removeListener(Listener listener) {
listeners.remove(listener);
}
}

View File

@ -1,5 +0,0 @@
package io.bisq.common;
public class CommonOptionKeys {
public static final String LOG_LEVEL_KEY = "logLevel";
}

View File

@ -1,7 +0,0 @@
package io.bisq.common;
/**
* Interface for the outside envelope object sent over the network or persisted to disc.
*/
public interface Envelope extends Proto {
}

View File

@ -1,88 +0,0 @@
package io.bisq.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.util.UUID;
/**
* We simulate a global frame rate timer similar to FXTimer to avoid creation of threads for each timer call.
* Used only in headless apps like the seed node.
*/
public class FrameRateTimer implements Timer, Runnable {
private final Logger log = LoggerFactory.getLogger(FrameRateTimer.class);
private long interval;
private Runnable runnable;
private long startTs;
private boolean isPeriodically;
private final String uid = UUID.randomUUID().toString();
private volatile boolean stopped;
public FrameRateTimer() {
}
@Override
public void run() {
if (!stopped) {
try {
long currentTimeMillis = System.currentTimeMillis();
if ((currentTimeMillis - startTs) >= interval) {
runnable.run();
if (isPeriodically)
startTs = currentTimeMillis;
else
stop();
}
} catch (Throwable t) {
log.error(t.getMessage());
t.printStackTrace();
stop();
throw t;
}
}
}
@Override
public Timer runLater(Duration delay, Runnable runnable) {
this.interval = delay.toMillis();
this.runnable = runnable;
startTs = System.currentTimeMillis();
MasterTimer.addListener(this);
return this;
}
@Override
public Timer runPeriodically(Duration interval, Runnable runnable) {
this.interval = interval.toMillis();
isPeriodically = true;
this.runnable = runnable;
startTs = System.currentTimeMillis();
MasterTimer.addListener(this);
return this;
}
@Override
public void stop() {
stopped = true;
MasterTimer.removeListener(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FrameRateTimer)) return false;
FrameRateTimer that = (FrameRateTimer) o;
return !(uid != null ? !uid.equals(that.uid) : that.uid != null);
}
@Override
public int hashCode() {
return uid != null ? uid.hashCode() : 0;
}
}

View File

@ -1,72 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common;
import io.bisq.common.locale.TradeCurrency;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import java.util.Locale;
public class GlobalSettings {
private static boolean useAnimations = true;
private static Locale locale = Locale.getDefault();
private static final ObjectProperty<Locale> localeProperty = new SimpleObjectProperty<>(locale);
private static TradeCurrency defaultTradeCurrency;
private static String btcDenomination;
public static void setLocale(Locale locale) {
GlobalSettings.locale = locale;
localeProperty.set(locale);
}
public static void setUseAnimations(boolean useAnimations) {
GlobalSettings.useAnimations = useAnimations;
}
public static void setDefaultTradeCurrency(TradeCurrency fiatCurrency) {
GlobalSettings.defaultTradeCurrency = fiatCurrency;
}
public static void setBtcDenomination(String btcDenomination) {
GlobalSettings.btcDenomination = btcDenomination;
}
public static TradeCurrency getDefaultTradeCurrency() {
return defaultTradeCurrency;
}
public static String getBtcDenomination() {
return btcDenomination;
}
public static ReadOnlyObjectProperty<Locale> localeProperty() {
return localeProperty;
}
public static boolean getUseAnimations() {
return useAnimations;
}
public static Locale getLocale() {
return locale;
}
}

View File

@ -1,35 +0,0 @@
package io.bisq.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArraySet;
// Runs all listener objects periodically in a short interval.
public class MasterTimer {
private final static Logger log = LoggerFactory.getLogger(MasterTimer.class);
private static final java.util.Timer timer = new java.util.Timer();
// frame rate of 60 fps is about 16 ms but we don't need such a short interval, 100 ms should be good enough
public static final long FRAME_INTERVAL_MS = 100;
static {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
UserThread.execute(() -> listeners.stream().forEach(Runnable::run));
}
}, FRAME_INTERVAL_MS, FRAME_INTERVAL_MS);
}
private static final Set<Runnable> listeners = new CopyOnWriteArraySet<>();
public static void addListener(Runnable runnable) {
listeners.add(runnable);
}
public static void removeListener(Runnable runnable) {
listeners.remove(runnable);
}
}

View File

@ -1,7 +0,0 @@
package io.bisq.common;
/**
* Interface for objects used inside an Envelope or other Payloads.
*/
public interface Payload extends Proto {
}

View File

@ -1,27 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common;
import com.google.protobuf.Message;
/**
* Base interface for Envelope and Payload.
*/
public interface Proto {
Message toProtoMessage();
}

View File

@ -1,11 +0,0 @@
package io.bisq.common;
import java.time.Duration;
public interface Timer {
Timer runLater(java.time.Duration delay, Runnable action);
Timer runPeriodically(Duration interval, Runnable runnable);
void stop();
}

View File

@ -1,96 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common;
import com.google.common.util.concurrent.MoreExecutors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.time.Duration;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
// Helps run delayed and periodic actions in the caller thread.
public class UserThread {
private static final Logger log = LoggerFactory.getLogger(UserThread.class);
private static Class<? extends Timer> timerClass;
public static Executor getExecutor() {
return executor;
}
public static void setExecutor(Executor executor) {
UserThread.executor = executor;
}
public static void setTimerClass(Class<? extends Timer> timerClass) {
UserThread.timerClass = timerClass;
}
static {
// If not defined we use same thread as caller thread
executor = MoreExecutors.directExecutor();
timerClass = FrameRateTimer.class;
}
private static Executor executor;
public static void execute(Runnable command) {
UserThread.executor.execute(command);
}
// Prefer FxTimer if a delay is needed in a JavaFx class (gui module)
public static Timer runAfterRandomDelay(Runnable runnable, long minDelayInSec, long maxDelayInSec) {
return UserThread.runAfterRandomDelay(runnable, minDelayInSec, maxDelayInSec, TimeUnit.SECONDS);
}
@SuppressWarnings("WeakerAccess")
public static Timer runAfterRandomDelay(Runnable runnable, long minDelay, long maxDelay, TimeUnit timeUnit) {
return UserThread.runAfter(runnable, new Random().nextInt((int) (maxDelay - minDelay)) + minDelay, timeUnit);
}
public static Timer runAfter(Runnable runnable, long delayInSec) {
return UserThread.runAfter(runnable, delayInSec, TimeUnit.SECONDS);
}
public static Timer runAfter(Runnable runnable, long delay, TimeUnit timeUnit) {
return getTimer().runLater(Duration.ofMillis(timeUnit.toMillis(delay)), runnable);
}
public static Timer runPeriodically(Runnable runnable, long intervalInSec) {
return UserThread.runPeriodically(runnable, intervalInSec, TimeUnit.SECONDS);
}
public static Timer runPeriodically(Runnable runnable, long interval, TimeUnit timeUnit) {
return getTimer().runPeriodically(Duration.ofMillis(timeUnit.toMillis(interval)), runnable);
}
private static Timer getTimer() {
try {
return timerClass.getDeclaredConstructor().newInstance();
} catch (InstantiationException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
String message = "Could not instantiate timer bsTimerClass=" + timerClass;
log.error(message);
e.printStackTrace();
throw new RuntimeException(message);
}
}
}

View File

@ -1,66 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.app;
import com.google.common.base.Preconditions;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import org.springframework.core.env.Environment;
import java.util.ArrayList;
import java.util.List;
public abstract class AppModule extends AbstractModule {
protected final Environment environment;
private final List<AppModule> modules = new ArrayList<>();
protected AppModule(Environment environment) {
Preconditions.checkNotNull(environment, "Environment must not be null");
this.environment = environment;
}
protected void install(AppModule module) {
super.install(module);
modules.add(module);
}
/**
* Close any instances this module is responsible for and recursively close any
* sub-modules installed via {@link #install(AppModule)}. This method
* must be called manually, e.g. at the end of a main() method or in the stop() method
* of a JavaFX Application; alternatively it may be registered as a JVM shutdown hook.
*
* @param injector the Injector originally initialized with this module
* @see #doClose(com.google.inject.Injector)
*/
public final void close(Injector injector) {
modules.forEach(module -> module.close(injector));
doClose(injector);
}
/**
* Actually perform closing of any instances this module is responsible for. Called by
* {@link #close(Injector)}.
*
* @param injector the Injector originally initialized with this module
*/
@SuppressWarnings({"WeakerAccess", "EmptyMethod", "UnusedParameters"})
protected void doClose(Injector injector) {
}
}

View File

@ -1,47 +0,0 @@
package io.bisq.common.app;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Capabilities {
// We can define here special features the client is supporting.
// Useful for updates to new versions where a new data type would break backwards compatibility or to
// limit a node to certain behaviour and roles like the seed nodes.
// We don't use the Enum in any serialized data, as changes in the enum would break backwards compatibility. We use the ordinal integer instead.
// Sequence in the enum must not be changed (append only).
public enum Capability {
TRADE_STATISTICS,
TRADE_STATISTICS_2,
ACCOUNT_AGE_WITNESS,
SEED_NODE,
DAO_FULL_NODE,
COMP_REQUEST
}
// Application need to set supported capabilities at startup
@Getter
@Setter
private static ArrayList<Integer> supportedCapabilities = new ArrayList<>();
public static boolean isCapabilitySupported(final List<Integer> requiredItems, final List<Integer> supportedItems) {
if (requiredItems != null && !requiredItems.isEmpty()) {
if (supportedItems != null && !supportedItems.isEmpty()) {
List<Integer> matches = new ArrayList<>();
for (int requiredItem : requiredItems) {
matches.addAll(supportedItems.stream()
.filter(supportedItem -> requiredItem == supportedItem)
.collect(Collectors.toList()));
}
return matches.size() == requiredItems.size();
} else {
return false;
}
} else {
return true;
}
}
}

View File

@ -1,30 +0,0 @@
package io.bisq.common.app;
public class DevEnv {
// Was used for P2P network stress test to adjust several setting for the tests (e.g. use lower btc fees for offers,..)
public static final boolean STRESS_TEST_MODE = false;
// The UI got set the private dev key so the developer does not need to do anything and can test those features.
// Features: Arbitration registration (alt+R at account), Alert/Update (alt+m), private message to a
// peer (click user icon and alt+r), filter/block offers by various data like offer ID (cmd + f).
// The user can set a program argument to ignore all of those privileged network_messages. They are intended for
// emergency cases only (beside update message and arbitrator registration).
public static final String DEV_PRIVILEGE_PUB_KEY = "027a381b5333a56e1cc3d90d3a7d07f26509adf7029ed06fc997c656621f8da1ee";
public static final String DEV_PRIVILEGE_PRIV_KEY = "6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a";
// If set to true we ignore several UI behavior like confirmation popups as well dummy accounts are created and
// offers are filled with default values. Intended to make dev testing faster.
@SuppressWarnings("PointlessBooleanExpression")
private static boolean devMode = false;
public static boolean isDevMode() {
return devMode;
}
public static void setDevMode(boolean devMode) {
DevEnv.devMode = devMode;
}
public static final boolean DAO_PHASE2_ACTIVATED = false;
public static final boolean DAO_TRADING_ACTIVATED = false;
}

View File

@ -1,122 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.app;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
import ch.qos.logback.core.util.FileSize;
import io.bisq.common.util.Profiler;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Log {
private static Logger logbackLogger;
public static void setLevel(Level logLevel) {
logbackLogger.setLevel(logLevel);
}
public static void setup(String fileName) {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(loggerContext);
appender.setFile(fileName + ".log");
FixedWindowRollingPolicy rollingPolicy = new FixedWindowRollingPolicy();
rollingPolicy.setContext(loggerContext);
rollingPolicy.setParent(appender);
rollingPolicy.setFileNamePattern(fileName + "_%i.log");
rollingPolicy.setMinIndex(1);
rollingPolicy.setMaxIndex(10);
rollingPolicy.start();
SizeBasedTriggeringPolicy triggeringPolicy = new SizeBasedTriggeringPolicy();
triggeringPolicy.setMaxFileSize(FileSize.valueOf("10MB"));
triggeringPolicy.start();
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setContext(loggerContext);
encoder.setPattern("%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{15}: %msg %xEx%n");
encoder.start();
//noinspection unchecked
appender.setEncoder(encoder);
appender.setRollingPolicy(rollingPolicy);
//noinspection unchecked
appender.setTriggeringPolicy(triggeringPolicy);
appender.start();
logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
//noinspection unchecked
logbackLogger.addAppender(appender);
logbackLogger.setLevel(Level.INFO);
// log errors in separate file
// not working as expected still.... damn logback...
/* FileAppender errorAppender = new FileAppender();
errorAppender.setEncoder(encoder);
errorAppender.setName("Error");
errorAppender.setContext(loggerContext);
errorAppender.setFile(fileName + "_error.log");
LevelFilter levelFilter = new LevelFilter();
levelFilter.setLevel(Level.ERROR);
levelFilter.setOnMatch(FilterReply.ACCEPT);
levelFilter.setOnMismatch(FilterReply.DENY);
levelFilter.start();
errorAppender.addFilter(levelFilter);
errorAppender.start();
logbackLogger.addAppender(errorAppender);*/
}
public static void traceCall() {
if (LoggerFactory.getLogger(Log.class).isTraceEnabled()) {
StackTraceElement stackTraceElement = new Throwable().getStackTrace()[1];
String methodName = stackTraceElement.getMethodName();
if (methodName.equals("<init>"))
methodName = "Constructor ";
String className = stackTraceElement.getClassName();
LoggerFactory.getLogger(className).trace("Called: {}", methodName);
}
}
public static void traceCall(String message) {
if (LoggerFactory.getLogger(Log.class).isTraceEnabled()) {
StackTraceElement stackTraceElement = new Throwable().getStackTrace()[1];
String methodName = stackTraceElement.getMethodName();
if (methodName.equals("<init>"))
methodName = "Constructor ";
String className = stackTraceElement.getClassName();
LoggerFactory.getLogger(className).trace("Called: {} [{}]", methodName, message);
}
}
public static void logIfStressTests(String msg) {
if (DevEnv.STRESS_TEST_MODE)
System.err.println(new SimpleDateFormat("HH:mm:ss.SSS").format(new Date()) +
" - " + msg +
" / Memory(MB): " + Profiler.getUsedMemoryInMB());
}
}

View File

@ -1,124 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.app;
import lombok.extern.slf4j.Slf4j;
import static com.google.common.base.Preconditions.checkArgument;
@Slf4j
public class Version {
// The application versions
// VERSION = 0.5.0 introduces proto buffer for the P2P network and local DB and is a not backward compatible update
// Therefore all sub versions start again with 1
// We use semantic versioning with major, minor and patch
public static final String VERSION = "0.6.7";
public static int getMajorVersion(String version) {
return getSubVersion(version, 0);
}
public static int getMinorVersion(String version) {
return getSubVersion(version, 1);
}
public static int getPatchVersion(String version) {
return getSubVersion(version, 2);
}
public static boolean isNewVersion(String newVersion) {
return isNewVersion(newVersion, VERSION);
}
static boolean isNewVersion(String newVersion, String currentVersion) {
if (newVersion.equals(currentVersion))
return false;
else if (getMajorVersion(newVersion) > getMajorVersion(currentVersion))
return true;
else if (getMajorVersion(newVersion) < getMajorVersion(currentVersion))
return false;
else if (getMinorVersion(newVersion) > getMinorVersion(currentVersion))
return true;
else if (getMinorVersion(newVersion) < getMinorVersion(currentVersion))
return false;
else if (getPatchVersion(newVersion) > getPatchVersion(currentVersion))
return true;
else if (getPatchVersion(newVersion) < getPatchVersion(currentVersion))
return false;
else
return false;
}
private static int getSubVersion(String version, int index) {
final String[] split = version.split("\\.");
checkArgument(split.length == 3, "Version number must be in semantic version format (contain 2 '.'). version=" + version);
return Integer.parseInt(split[index]);
}
// The version no. for the objects sent over the network. A change will break the serialization of old objects.
// If objects are used for both network and database the network version is applied.
// VERSION = 0.5.0 -> P2P_NETWORK_VERSION = 1
@SuppressWarnings("ConstantConditions")
public static final int P2P_NETWORK_VERSION = DevEnv.STRESS_TEST_MODE ? 100 : 1;
// The version no. of the serialized data stored to disc. A change will break the serialization of old objects.
// VERSION = 0.5.0 -> LOCAL_DB_VERSION = 1
public static final int LOCAL_DB_VERSION = 1;
// The version no. of the current protocol. The offer holds that version.
// A taker will check the version of the offers to see if his version is compatible.
// VERSION = 0.5.0 -> TRADE_PROTOCOL_VERSION = 1
public static final int TRADE_PROTOCOL_VERSION = 1;
private static int p2pMessageVersion;
public static final String BSQ_TX_VERSION = "1";
public static int getP2PMessageVersion() {
return p2pMessageVersion;
}
// The version for the crypto network (BTC_Mainnet = 0, BTC_TestNet = 1, BTC_Regtest = 2, ...)
private static int BASE_CURRENCY_NETWORK;
public static void setBaseCryptoNetworkId(int baseCryptoNetworkId) {
BASE_CURRENCY_NETWORK = baseCryptoNetworkId;
// CRYPTO_NETWORK_ID is ordinal of enum. We use for changes at NETWORK_PROTOCOL_VERSION a multiplication with 10
// to not mix up networks:
p2pMessageVersion = BASE_CURRENCY_NETWORK + 10 * P2P_NETWORK_VERSION;
}
public static int getBaseCurrencyNetwork() {
return BASE_CURRENCY_NETWORK;
}
public static void printVersion() {
log.info("Version{" +
"VERSION=" + VERSION +
", P2P_NETWORK_VERSION=" + P2P_NETWORK_VERSION +
", LOCAL_DB_VERSION=" + LOCAL_DB_VERSION +
", TRADE_PROTOCOL_VERSION=" + TRADE_PROTOCOL_VERSION +
", BASE_CURRENCY_NETWORK=" + BASE_CURRENCY_NETWORK +
", getP2PNetworkId()=" + getP2PMessageVersion() +
'}');
}
public static final byte COMPENSATION_REQUEST_VERSION = (byte) 0x01;
public static final byte VOTING_VERSION = (byte) 0x01;
public static final byte VOTING_RELEASE_VERSION = (byte) 0x01;
}

View File

@ -1,32 +0,0 @@
/*
* This file is part of bisq.
*
* bisq 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.
*
* bisq 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 bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.consensus;
/**
* Marker interface for classes which are used in the trade contract.
* Any change of the class fields would breaking backward compatibility.
* If a field needs to get added it needs to be annotated with @JsonExclude (thus excluded from the contract JSON).
* Better to use the excludeFromJsonDataMap (annotated with @JsonExclude; used in PaymentAccountPayload) to
* add a key/value pair.
*/
// TODO PubKeyRing and NodeAddress (network) are using UsedForTradeContractJson that is why it is in common module,
// which is a bit weird... Maybe we need either rename common or split it to util and common where common is common code
// used in network and core?
public interface UsedForTradeContractJson {
}

View File

@ -1,32 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
public class CryptoException extends Exception {
public CryptoException(String message) {
super(message);
}
public CryptoException(String message, Throwable cause) {
super(message, cause);
}
public CryptoException(Throwable cause) {
super(cause);
}
}

View File

@ -1,40 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
import lombok.extern.slf4j.Slf4j;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
@Slf4j
public class CryptoUtils {
public static String pubKeyToString(PublicKey publicKey) {
final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
return Base64.getEncoder().encodeToString(x509EncodedKeySpec.getEncoded());
}
public static byte[] getRandomBytes(int size) {
byte[] bytes = new byte[size];
new SecureRandom().nextBytes(bytes);
return bytes;
}
}

View File

@ -1,237 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
import io.bisq.common.util.Utilities;
import org.bouncycastle.util.encoders.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
// TODO is Hmac needed/make sense?
public class Encryption {
private static final Logger log = LoggerFactory.getLogger(Encryption.class);
public static final String ASYM_KEY_ALGO = "RSA";
private static final String ASYM_CIPHER = "RSA/None/OAEPWithSHA256AndMGF1Padding";
private static final String SYM_KEY_ALGO = "AES";
private static final String SYM_CIPHER = "AES";
private static final String HMAC = "HmacSHA256";
public static KeyPair generateKeyPair() {
long ts = System.currentTimeMillis();
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ASYM_KEY_ALGO, "BC");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.genKeyPair();
log.trace("Generate msgEncryptionKeyPair needed {} ms", System.currentTimeMillis() - ts);
return keyPair;
} catch (Throwable e) {
log.error(e.toString());
e.printStackTrace();
throw new RuntimeException("Could not create key.");
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Symmetric
///////////////////////////////////////////////////////////////////////////////////////////
private static byte[] encrypt(byte[] payload, SecretKey secretKey) throws CryptoException {
try {
Cipher cipher = Cipher.getInstance(SYM_CIPHER, "BC");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(payload);
} catch (Throwable e) {
e.printStackTrace();
throw new CryptoException(e);
}
}
private static byte[] decrypt(byte[] encryptedPayload, SecretKey secretKey) throws CryptoException {
try {
Cipher cipher = Cipher.getInstance(SYM_CIPHER, "BC");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(encryptedPayload);
} catch (Throwable e) {
throw new CryptoException(e);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Hmac
///////////////////////////////////////////////////////////////////////////////////////////
private static byte[] getPayloadWithHmac(byte[] payload, SecretKey secretKey) {
byte[] payloadWithHmac;
try {
ByteArrayOutputStream outputStream = null;
try {
byte[] hmac = getHmac(payload, secretKey);
outputStream = new ByteArrayOutputStream();
outputStream.write(payload);
outputStream.write(hmac);
outputStream.flush();
payloadWithHmac = outputStream.toByteArray().clone();
} catch (IOException | NoSuchProviderException e) {
log.error(e.toString());
e.printStackTrace();
throw new RuntimeException("Could not create hmac");
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException ignored) {
}
}
}
} catch (Throwable e) {
log.error(e.toString());
e.printStackTrace();
throw new RuntimeException("Could not create hmac");
}
return payloadWithHmac;
}
private static boolean verifyHmac(byte[] message, byte[] hmac, SecretKey secretKey) {
try {
byte[] hmacTest = getHmac(message, secretKey);
return Arrays.equals(hmacTest, hmac);
} catch (Throwable e) {
log.error(e.toString());
e.printStackTrace();
throw new RuntimeException("Could not create cipher");
}
}
private static byte[] getHmac(byte[] payload, SecretKey secretKey) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
Mac mac = Mac.getInstance(HMAC, "BC");
mac.init(secretKey);
return mac.doFinal(payload);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Symmetric with Hmac
///////////////////////////////////////////////////////////////////////////////////////////
public static byte[] encryptPayloadWithHmac(byte[] payload, SecretKey secretKey) throws CryptoException {
return encrypt(getPayloadWithHmac(payload, secretKey), secretKey);
}
public static byte[] decryptPayloadWithHmac(byte[] encryptedPayloadWithHmac, SecretKey secretKey) throws CryptoException {
byte[] payloadWithHmac = decrypt(encryptedPayloadWithHmac, secretKey);
String payloadWithHmacAsHex = Hex.toHexString(payloadWithHmac);
// first part is raw message
int length = payloadWithHmacAsHex.length();
int sep = length - 64;
String payloadAsHex = payloadWithHmacAsHex.substring(0, sep);
// last 64 bytes is hmac
String hmacAsHex = payloadWithHmacAsHex.substring(sep, length);
if (verifyHmac(Hex.decode(payloadAsHex), Hex.decode(hmacAsHex), secretKey)) {
return Hex.decode(payloadAsHex);
} else {
throw new CryptoException("Hmac does not match.");
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Asymmetric
///////////////////////////////////////////////////////////////////////////////////////////
public static byte[] encryptSecretKey(SecretKey secretKey, PublicKey publicKey) throws CryptoException {
try {
Cipher cipher = Cipher.getInstance(ASYM_CIPHER, "BC");
cipher.init(Cipher.WRAP_MODE, publicKey);
return cipher.wrap(secretKey);
} catch (Throwable e) {
e.printStackTrace();
throw new CryptoException("Couldn't encrypt payload");
}
}
public static SecretKey decryptSecretKey(byte[] encryptedSecretKey, PrivateKey privateKey) throws CryptoException {
try {
Cipher cipher = Cipher.getInstance(ASYM_CIPHER, "BC");
cipher.init(Cipher.UNWRAP_MODE, privateKey);
return (SecretKey) cipher.unwrap(encryptedSecretKey, "AES", Cipher.SECRET_KEY);
} catch (Throwable e) {
// errors when trying to decrypt foreign network_messages are normal
throw new CryptoException(e);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Hybrid with signature of asymmetric key
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
public static SecretKey generateSecretKey() {
try {
KeyGenerator keyPairGenerator = KeyGenerator.getInstance(SYM_KEY_ALGO, "BC");
keyPairGenerator.init(256);
return keyPairGenerator.generateKey();
} catch (Throwable e) {
e.printStackTrace();
log.error(e.getMessage());
throw new RuntimeException("Couldn't generate key");
}
}
public static byte[] getPublicKeyBytes(PublicKey encryptionPubKey) {
return new X509EncodedKeySpec(encryptionPubKey.getEncoded()).getEncoded();
}
/**
* @param encryptionPubKeyBytes
* @return
*/
public static PublicKey getPublicKeyFromBytes(byte[] encryptionPubKeyBytes) {
try {
return KeyFactory.getInstance(Encryption.ASYM_KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(encryptionPubKeyBytes));
} catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) {
log.error("Error creating sigPublicKey from bytes. sigPublicKeyBytes as hex={}, error={}", Utilities.bytesAsHexString(encryptionPubKeyBytes), e);
e.printStackTrace();
throw new KeyConversionException(e);
}
}
}

View File

@ -1,72 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
import com.google.common.base.Charsets;
import lombok.extern.slf4j.Slf4j;
import org.bitcoinj.core.Utils;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
@Slf4j
public class Hash {
/**
* @param data Data as byte array
* @return Hash of data
*/
public static byte[] getSha256Hash(byte[] data) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256", "BC");
digest.update(data, 0, data.length);
return digest.digest();
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
log.error("Could not create MessageDigest for hash. " + e.toString());
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* @param message UTF-8 encoded message
* @return Hash of data
*/
public static byte[] getSha256Hash(String message) {
return getSha256Hash(message.getBytes(Charsets.UTF_8));
}
/**
* @param data data as Integer
* @return Hash of data
*/
public static byte[] getSha256Hash(Integer data) {
return getSha256Hash(ByteBuffer.allocate(4).putInt(data).array());
}
/**
* Calculates RIPEMD160(SHA256(input)).
*/
public static byte[] getSha256Ripemd160hash(byte[] data) {
return Utils.sha256hash160(data);
}
}

View File

@ -1,28 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
public class KeyConversionException extends RuntimeException {
public KeyConversionException(Throwable cause) {
super(cause);
}
public KeyConversionException(String msg) {
super(msg);
}
}

View File

@ -1,77 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKey;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.security.KeyPair;
@Getter
@EqualsAndHashCode
@Slf4j
public class KeyRing {
private final KeyPair signatureKeyPair;
private final KeyPair encryptionKeyPair;
private final PubKeyRing pubKeyRing;
// We generate by default a PGP keypair but the user can set his own if he prefers.
// Not impl. yet but prepared in data structure
@Nullable
@Setter
// TODO remove Nullable once impl.
private PGPKeyPair pgpKeyPair;
@Inject
public KeyRing(KeyStorage keyStorage) {
if (keyStorage.allKeyFilesExist()) {
signatureKeyPair = keyStorage.loadKeyPair(KeyStorage.KeyEntry.MSG_SIGNATURE);
encryptionKeyPair = keyStorage.loadKeyPair(KeyStorage.KeyEntry.MSG_ENCRYPTION);
// TODO not impl
pgpKeyPair = keyStorage.loadPgpKeyPair(KeyStorage.KeyEntry.PGP);
} else {
// First time we create key pairs
signatureKeyPair = Sig.generateKeyPair();
encryptionKeyPair = Encryption.generateKeyPair();
// TODO not impl
pgpKeyPair = PGP.generateKeyPair();
keyStorage.saveKeyRing(this);
}
// TODO remove Nullable once impl.
final PGPPublicKey pgpPublicKey = pgpKeyPair != null ? pgpKeyPair.getPublicKey() : null;
pubKeyRing = new PubKeyRing(signatureKeyPair.getPublic(), encryptionKeyPair.getPublic(), pgpPublicKey);
}
// Don't print keys for security reasons
@Override
public String toString() {
return "KeyRing{" +
"signatureKeyPair.hashCode()=" + signatureKeyPair.hashCode() +
", encryptionKeyPair.hashCode()=" + encryptionKeyPair.hashCode() +
", pubKeyRing.hashCode()=" + pubKeyRing.hashCode() +
'}';
}
}

View File

@ -1,169 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
import com.google.inject.Inject;
import io.bisq.common.storage.FileUtil;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.inject.Named;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.*;
import java.util.Date;
// TODO: use a password protection for key storage
public class KeyStorage {
private static final Logger log = LoggerFactory.getLogger(KeyStorage.class);
public static final String KEY_STORAGE_DIR = "keyStorageDir";
public enum KeyEntry {
MSG_SIGNATURE("sig", Sig.KEY_ALGO),
MSG_ENCRYPTION("enc", Encryption.ASYM_KEY_ALGO),
// TODO not impl
PGP("pgp", null);
private final String fileName;
private final String algorithm;
KeyEntry(String fileName, String algorithm) {
this.fileName = fileName;
this.algorithm = algorithm;
}
public String getFileName() {
return fileName;
}
public String getAlgorithm() {
return algorithm;
}
@NotNull
@Override
public String toString() {
return "Key{" +
"fileName='" + fileName + '\'' +
", algorithm='" + algorithm + '\'' +
'}';
}
}
private final File storageDir;
@Inject
public KeyStorage(@Named(KEY_STORAGE_DIR) File storageDir) {
this.storageDir = storageDir;
}
public boolean allKeyFilesExist() {
return fileExists(KeyEntry.MSG_SIGNATURE) && fileExists(KeyEntry.MSG_ENCRYPTION);
}
private boolean fileExists(KeyEntry keyEntry) {
return new File(storageDir + "/" + keyEntry.getFileName() + ".key").exists();
}
// TODO not impl
@SuppressWarnings({"SameParameterValue", "SameReturnValue", "UnusedParameters"})
@Nullable
public PGPKeyPair loadPgpKeyPair(KeyEntry keyEntry) {
return null;
}
public KeyPair loadKeyPair(KeyEntry keyEntry) {
FileUtil.rollingBackup(storageDir, keyEntry.getFileName() + ".key", 20);
// long now = System.currentTimeMillis();
try {
KeyFactory keyFactory = KeyFactory.getInstance(keyEntry.getAlgorithm(), "BC");
PublicKey publicKey;
PrivateKey privateKey;
File filePrivateKey = new File(storageDir + "/" + keyEntry.getFileName() + ".key");
try (FileInputStream fis = new FileInputStream(filePrivateKey.getPath())) {
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
//noinspection ResultOfMethodCallIgnored
fis.read(encodedPrivateKey);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
privateKey = keyFactory.generatePrivate(privateKeySpec);
} catch (InvalidKeySpecException | IOException e) {
log.error(e.getMessage());
e.printStackTrace();
throw new RuntimeException("Could not load key " + keyEntry.toString(), e);
}
if (privateKey instanceof RSAPrivateCrtKey) {
RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey;
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(rsaPrivateKey.getModulus(), rsaPrivateKey.getPublicExponent());
publicKey = keyFactory.generatePublic(publicKeySpec);
} else if (privateKey instanceof DSAPrivateKey) {
DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) privateKey;
DSAParams dsaParams = dsaPrivateKey.getParams();
BigInteger p = dsaParams.getP();
BigInteger q = dsaParams.getQ();
BigInteger g = dsaParams.getG();
BigInteger y = g.modPow(dsaPrivateKey.getX(), p);
KeySpec publicKeySpec = new DSAPublicKeySpec(y, p, q, g);
publicKey = keyFactory.generatePublic(publicKeySpec);
} else {
throw new RuntimeException("Unsupported key algo" + keyEntry.getAlgorithm());
}
log.debug("load completed in {} msec", System.currentTimeMillis() - new Date().getTime());
return new KeyPair(publicKey, privateKey);
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) {
e.printStackTrace();
log.error(e.getMessage());
throw new RuntimeException("Could not load key " + keyEntry.toString(), e);
}
}
public void saveKeyRing(KeyRing keyRing) {
savePrivateKey(keyRing.getSignatureKeyPair().getPrivate(), KeyEntry.MSG_SIGNATURE.getFileName());
savePrivateKey(keyRing.getEncryptionKeyPair().getPrivate(), KeyEntry.MSG_ENCRYPTION.getFileName());
}
private void savePrivateKey(PrivateKey privateKey, String name) {
if (!storageDir.exists())
//noinspection ResultOfMethodCallIgnored
storageDir.mkdir();
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
try (FileOutputStream fos = new FileOutputStream(storageDir + "/" + name + ".key")) {
fos.write(pkcs8EncodedKeySpec.getEncoded());
} catch (IOException e) {
log.error(e.toString());
e.printStackTrace();
throw new RuntimeException("Could not save key " + name, e);
}
}
}

View File

@ -1,24 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
public class LimitedKeyStrengthException extends Exception {
public LimitedKeyStrengthException() {
super("Default crypto policy has not been changed. Only weak keys with length 128 are allowed by the default policy.");
}
}

View File

@ -1,122 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection;
import org.bouncycastle.util.encoders.Hex;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.Iterator;
@SuppressWarnings("UnusedAssignment")
@Slf4j
public class PGP {
// TODO not tested yet, remove Nullable once impl.
// PEM encoding
@Nullable
public static PGPPublicKey getPubKeyFromPem(@Nullable String pem) {
if (pem != null) {
InputStream inputStream = new ByteArrayInputStream(pem.getBytes());
try {
inputStream = PGPUtil.getDecoderStream(inputStream);
try {
JcaPGPPublicKeyRingCollection ringCollection = new JcaPGPPublicKeyRingCollection(inputStream);
Iterator<PGPPublicKeyRing> keyRingsIterator = ringCollection.getKeyRings();
while (keyRingsIterator.hasNext()) {
PGPPublicKeyRing pgpPublicKeyRing = keyRingsIterator.next();
Iterator<PGPPublicKey> pubKeysIterator = pgpPublicKeyRing.getPublicKeys();
while (pubKeysIterator.hasNext()) {
final PGPPublicKey pgpPublicKey = pubKeysIterator.next();
if ((pgpPublicKey).isEncryptionKey()) {
log.debug(pgpPublicKey.getClass().getName()
+ " KeyID: " + Long.toHexString(pgpPublicKey.getKeyID())
+ " type: " + pgpPublicKey.getAlgorithm()
+ " fingerprint: " + new String(Hex.encode(pgpPublicKey.getFingerprint())));
BCPGKey bcKey = pgpPublicKey.getPublicKeyPacket().getKey();
log.debug(bcKey.getClass().getName());
if (bcKey instanceof RSAPublicBCPGKey) {
RSAPublicBCPGKey bcRSA = (RSAPublicBCPGKey) bcKey;
RSAPublicKeySpec specRSA = new RSAPublicKeySpec(bcRSA.getModulus(), bcRSA.getPublicExponent());
PublicKey jceKey = KeyFactory.getInstance("RSA").generatePublic(specRSA);
// if you want to use the key in JCE, use jceKey
// if you want to write "X.509" (SPKI) DER format to a file:
//Files.write(new File(pubKeyAsString).toPath(), jceKey.getEncoded());
// if you want to write in PEM, bouncycastle can do that
// or you can just do base64 and add BEGIN/END lines
// return pubKeyAsString; // assume only one key; if need to handle multiple keys
// or select other than the first, specify more clearly
}
return pgpPublicKey;
}
}
}
return null;
} catch (PGPException | InvalidKeySpecException | NoSuchAlgorithmException e) {
log.error("Error creating publicKey from pem. pem={}, error={}", pem, e);
e.printStackTrace();
throw new KeyConversionException(e);
}
} catch (IOException e) {
log.error("Error creating publicKey from pem. pem={}, error={}", pem, e);
e.printStackTrace();
throw new KeyConversionException(e);
} finally {
try {
inputStream.close();
} catch (IOException ignore) {
}
}
} else {
log.warn("Error creating publicKey from pem. pem=null");
return null;
}
}
// TODO not impl, remove Nullable once impl.
// PEM encoding
@SuppressWarnings({"SameReturnValue", "UnusedParameters"})
@NotNull
public static String getPEMFromPubKey(@Nullable PGPPublicKey pgpPubKey) {
// We use empty string as we must not have null in proto file
return "";
}
// TODO not impl, remove Nullable once impl.
@SuppressWarnings("SameReturnValue")
@Nullable
public static PGPKeyPair generateKeyPair() {
return null;
}
}

View File

@ -1,102 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
import com.google.common.annotations.VisibleForTesting;
import com.google.protobuf.ByteString;
import io.bisq.common.consensus.UsedForTradeContractJson;
import io.bisq.common.proto.network.NetworkPayload;
import io.bisq.common.util.Utilities;
import io.bisq.generated.protobuffer.PB;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.openpgp.PGPPublicKey;
import javax.annotation.Nullable;
import java.security.PublicKey;
/**
* Same as KeyRing but with public keys only.
* Used to send public keys over the wire to other peer.
*/
@Slf4j
@EqualsAndHashCode
@Getter
public final class PubKeyRing implements NetworkPayload, UsedForTradeContractJson {
private final byte[] signaturePubKeyBytes;
private final byte[] encryptionPubKeyBytes;
@Nullable
private final String pgpPubKeyAsPem;
private transient PublicKey signaturePubKey;
private transient PublicKey encryptionPubKey;
@Nullable
private transient PGPPublicKey pgpPubKey;
public PubKeyRing(PublicKey signaturePubKey, PublicKey encryptionPubKey, @Nullable PGPPublicKey pgpPubKey) {
this.signaturePubKeyBytes = Sig.getPublicKeyBytes(signaturePubKey);
this.encryptionPubKeyBytes = Encryption.getPublicKeyBytes(encryptionPubKey);
this.pgpPubKeyAsPem = PGP.getPEMFromPubKey(pgpPubKey);
this.signaturePubKey = signaturePubKey;
this.encryptionPubKey = encryptionPubKey;
this.pgpPubKey = pgpPubKey;
}
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
@VisibleForTesting
public PubKeyRing(byte[] signaturePubKeyBytes, byte[] encryptionPubKeyBytes, @Nullable String pgpPubKeyAsPem) {
this.signaturePubKeyBytes = signaturePubKeyBytes;
this.encryptionPubKeyBytes = encryptionPubKeyBytes;
this.pgpPubKeyAsPem = pgpPubKeyAsPem;
signaturePubKey = Sig.getPublicKeyFromBytes(signaturePubKeyBytes);
encryptionPubKey = Encryption.getPublicKeyFromBytes(encryptionPubKeyBytes);
if (pgpPubKeyAsPem != null)
pgpPubKey = PGP.getPubKeyFromPem(pgpPubKeyAsPem);
}
@Override
public PB.PubKeyRing toProtoMessage() {
return PB.PubKeyRing.newBuilder()
.setSignaturePubKeyBytes(ByteString.copyFrom(signaturePubKeyBytes))
.setEncryptionPubKeyBytes(ByteString.copyFrom(encryptionPubKeyBytes))
.setPgpPubKeyAsPem(pgpPubKeyAsPem)
.build();
}
public static PubKeyRing fromProto(PB.PubKeyRing proto) {
return new PubKeyRing(proto.getSignaturePubKeyBytes().toByteArray(),
proto.getEncryptionPubKeyBytes().toByteArray(),
proto.getPgpPubKeyAsPem());
}
@Override
public String toString() {
return "PubKeyRing{" +
"signaturePubKeyHex=" + Utilities.bytesAsHexString(signaturePubKeyBytes) +
", encryptionPubKeyHex=" + Utilities.bytesAsHexString(encryptionPubKeyBytes) +
", pgpPubKeyAsString=" + pgpPubKeyAsPem +
'}';
}
}

View File

@ -1,79 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
import com.google.protobuf.ByteString;
import io.bisq.common.proto.network.NetworkPayload;
import io.bisq.generated.protobuffer.PB;
import lombok.Value;
import java.security.PublicKey;
@Value
public final class SealedAndSigned implements NetworkPayload {
private final byte[] encryptedSecretKey;
private final byte[] encryptedPayloadWithHmac;
private final byte[] signature;
private final byte[] sigPublicKeyBytes;
transient private final PublicKey sigPublicKey;
public SealedAndSigned(byte[] encryptedSecretKey,
byte[] encryptedPayloadWithHmac,
byte[] signature,
PublicKey sigPublicKey) {
this.encryptedSecretKey = encryptedSecretKey;
this.encryptedPayloadWithHmac = encryptedPayloadWithHmac;
this.signature = signature;
this.sigPublicKey = sigPublicKey;
sigPublicKeyBytes = Sig.getPublicKeyBytes(sigPublicKey);
}
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
private SealedAndSigned(byte[] encryptedSecretKey,
byte[] encryptedPayloadWithHmac,
byte[] signature,
byte[] sigPublicKeyBytes) {
this.encryptedSecretKey = encryptedSecretKey;
this.encryptedPayloadWithHmac = encryptedPayloadWithHmac;
this.signature = signature;
this.sigPublicKeyBytes = sigPublicKeyBytes;
sigPublicKey = Sig.getPublicKeyFromBytes(sigPublicKeyBytes);
}
public PB.SealedAndSigned toProtoMessage() {
return PB.SealedAndSigned.newBuilder()
.setEncryptedSecretKey(ByteString.copyFrom(encryptedSecretKey))
.setEncryptedPayloadWithHmac(ByteString.copyFrom(encryptedPayloadWithHmac))
.setSignature(ByteString.copyFrom(signature))
.setSigPublicKeyBytes(ByteString.copyFrom(sigPublicKeyBytes))
.build();
}
public static SealedAndSigned fromProto(PB.SealedAndSigned proto) {
return new SealedAndSigned(proto.getEncryptedSecretKey().toByteArray(),
proto.getEncryptedPayloadWithHmac().toByteArray(),
proto.getSignature().toByteArray(),
proto.getSigPublicKeyBytes().toByteArray());
}
}

View File

@ -1,147 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.crypto;
import com.google.common.base.Charsets;
import io.bisq.common.util.Utilities;
import org.bouncycastle.util.encoders.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
/**
* StorageSignatureKeyPair/STORAGE_SIGN_KEY_ALGO: That is used for signing the data to be stored to the P2P network (by flooding).
* The algo is selected because it originated from the TomP2P version which used DSA.
* Changing to EC keys might be considered.
* <p/>
* MsgSignatureKeyPair/MSG_SIGN_KEY_ALGO/MSG_SIGN_ALGO: That is used when sending a message to a peer which is encrypted and signed.
* Changing to EC keys might be considered.
*/
public class Sig {
private static final Logger log = LoggerFactory.getLogger(Sig.class);
public static final String KEY_ALGO = "DSA";
private static final String ALGO = "SHA256withDSA";
/**
* @return keyPair
*/
public static KeyPair generateKeyPair() {
long ts = System.currentTimeMillis();
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGO, "BC");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
log.trace("Generate msgSignatureKeyPair needed {} ms", System.currentTimeMillis() - ts);
return keyPair;
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
e.printStackTrace();
log.error(e.toString());
throw new RuntimeException("Could not create key.");
}
}
/**
* @param privateKey
* @param data
* @return
* @throws SignatureException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static byte[] sign(PrivateKey privateKey, byte[] data) throws CryptoException {
try {
Signature sig = Signature.getInstance(ALGO, "BC");
sig.initSign(privateKey);
sig.update(data);
return sig.sign();
} catch (SignatureException | NoSuchProviderException | InvalidKeyException | NoSuchAlgorithmException e) {
throw new CryptoException("Signing failed. " + e.getMessage());
}
}
/**
* @param privateKey
* @param message UTF-8 encoded message to sign
* @return Base64 encoded signature
* @throws SignatureException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static String sign(PrivateKey privateKey, String message) throws CryptoException {
byte[] sigAsBytes = sign(privateKey, message.getBytes(Charsets.UTF_8));
return Base64.toBase64String(sigAsBytes);
}
/**
* @param publicKey
* @param data
* @param signature
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
*/
public static boolean verify(PublicKey publicKey, byte[] data, byte[] signature) throws CryptoException {
try {
Signature sig = Signature.getInstance(ALGO, "BC");
sig.initVerify(publicKey);
sig.update(data);
return sig.verify(signature);
} catch (SignatureException | NoSuchProviderException | InvalidKeyException | NoSuchAlgorithmException e) {
throw new CryptoException("Signature verification failed. " + e.getMessage());
}
}
/**
* @param publicKey
* @param message UTF-8 encoded message
* @param signature Base64 encoded signature
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
*/
public static boolean verify(PublicKey publicKey, String message, String signature) throws CryptoException {
return verify(publicKey, message.getBytes(Charsets.UTF_8), Base64.decode(signature));
}
/**
* @param sigPublicKeyBytes
* @return
*/
public static PublicKey getPublicKeyFromBytes(byte[] sigPublicKeyBytes) {
try {
return KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(sigPublicKeyBytes));
} catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) {
log.error("Error creating sigPublicKey from bytes. sigPublicKeyBytes as hex={}, error={}", Utilities.bytesAsHexString(sigPublicKeyBytes), e);
e.printStackTrace();
throw new KeyConversionException(e);
}
}
public static byte[] getPublicKeyBytes(PublicKey sigPublicKey) {
return new X509EncodedKeySpec(sigPublicKey.getEncoded()).getEncoded();
}
}

View File

@ -1,25 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.handlers;
/**
* For reporting error message only (UI)
*/
public interface ErrorMessageHandler {
void handleErrorMessage(String errorMessage);
}

View File

@ -1,25 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.handlers;
/**
* For reporting throwable objects only
*/
public interface ExceptionHandler {
void handleException(Throwable throwable);
}

View File

@ -1,25 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.handlers;
/**
* For reporting a description message and throwable
*/
public interface FaultHandler {
void handleFault(String errorMessage, Throwable throwable);
}

View File

@ -1,22 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.handlers;
public interface ResultHandler {
void handleResult();
}

View File

@ -1,267 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class BankUtil {
private static final Logger log = LoggerFactory.getLogger(BankUtil.class);
// BankName
@SuppressWarnings("SameReturnValue")
public static boolean isBankNameRequired(String countryCode) {
switch (countryCode) {
case "GB":
case "US":
case "NZ":
case "AU":
case "CA":
case "SE":
case "HK":
// We show always the bank name as it is needed in specific banks.
// Though that handling should be optimized in futures.
return true;
// return false;
case "MX":
case "BR":
return true;
default:
return true;
}
}
public static String getBankNameLabel(String countryCode) {
switch (countryCode) {
case "BR":
return Res.get("payment.bank.name");
default:
return isBankNameRequired(countryCode) ? Res.get("payment.bank.name") : Res.get("payment.bank.nameOptional");
}
}
// BankId
public static boolean isBankIdRequired(String countryCode) {
switch (countryCode) {
case "GB":
case "US":
case "BR":
case "NZ":
case "AU":
case "SE":
case "CL":
case "NO":
return false;
case "CA":
case "MX":
case "HK":
return true;
default:
return true;
}
}
public static String getBankIdLabel(String countryCode) {
switch (countryCode) {
case "CA":
return "Institution Number:";// do not translate as it is used in english only
case "MX":
case "HK":
return Res.get("payment.bankCode");
default:
return isBankIdRequired(countryCode) ? Res.get("payment.bankId") : Res.get("payment.bankIdOptional");
}
}
// BranchId
public static boolean isBranchIdRequired(String countryCode) {
switch (countryCode) {
case "GB":
case "US":
case "BR":
case "AU":
case "CA":
return true;
case "NZ":
case "MX":
case "HK":
case "SE":
case "NO":
return false;
default:
return true;
}
}
public static String getBranchIdLabel(String countryCode) {
switch (countryCode) {
case "GB":
return "UK sort code:"; // do not translate as it is used in english only
case "US":
return "Routing Number:"; // do not translate as it is used in english only
case "BR":
return "Código da Agência:"; // do not translate as it is used in portuguese only
case "AU":
return "BSB code:"; // do not translate as it is used in english only
case "CA":
return "Transit Number:"; // do not translate as it is used in english only
default:
return isBranchIdRequired(countryCode) ? Res.get("payment.branchNr") : Res.get("payment.branchNrOptional");
}
}
// AccountNr
@SuppressWarnings("SameReturnValue")
public static boolean isAccountNrRequired(String countryCode) {
switch (countryCode) {
default:
return true;
}
}
public static String getAccountNrLabel(String countryCode) {
switch (countryCode) {
case "GB":
case "US":
case "BR":
case "NZ":
case "AU":
case "CA":
case "HK":
return Res.get("payment.accountNr");
case "NO":
return "Kontonummer:"; // do not translate as it is used in norwegian only
case "SE":
return "Bankgiro number:"; // do not translate as it is used in swedish only
case "MX":
return "CLABE:"; // do not translate as it is used in spanish only
case "CL":
return "Cuenta:"; // do not translate as it is used in spanish only
default:
return Res.get("payment.accountNrLabel");
}
}
// AccountType
public static boolean isAccountTypeRequired(String countryCode) {
switch (countryCode) {
case "US":
case "BR":
case "CA":
return true;
default:
return false;
}
}
public static String getAccountTypeLabel(String countryCode) {
switch (countryCode) {
case "US":
case "BR":
case "CA":
return Res.get("payment.accountType");
default:
return "";
}
}
public static List<String> getAccountTypeValues(String countryCode) {
switch (countryCode) {
case "US":
case "BR":
case "CA":
return Arrays.asList(Res.get("payment.checking"), Res.get("payment.savings"));
default:
return new ArrayList<>();
}
}
// HolderId
public static boolean isHolderIdRequired(String countryCode) {
switch (countryCode) {
case "BR":
case "CL":
return true;
default:
return false;
}
}
public static String getHolderIdLabel(String countryCode) {
switch (countryCode) {
case "BR":
return "Cadastro de Pessoas Físicas (CPF):"; // do not translate as it is used in portuguese only
case "CL":
return "Rol Único Tributario (RUT):"; // do not translate as it is used in spanish only
default:
return Res.get("payment.personalId");
}
}
public static String getHolderIdLabelShort(String countryCode) {
switch (countryCode) {
case "BR":
return "CPF:"; // do not translate as it is used in portuguese only
case "CL":
return "RUT:"; // do not translate as it is used in spanish only
default:
return "ID";
}
}
// Validation
public static boolean useValidation(String countryCode) {
switch (countryCode) {
case "GB":
case "US":
case "BR":
case "AU":
case "CA":
case "NZ":
case "MX":
case "HK":
case "SE":
case "NO":
return true;
default:
return false;
}
}
public static boolean isStateRequired(String countryCode) {
switch (countryCode) {
case "US":
case "CA":
case "AU":
case "MY":
case "MX":
case "CN":
return true;
default:
return false;
}
}
}

View File

@ -1,53 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import com.google.protobuf.Message;
import io.bisq.common.proto.persistable.PersistablePayload;
import io.bisq.generated.protobuffer.PB;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.annotation.concurrent.Immutable;
@Immutable
@EqualsAndHashCode
@ToString
public final class Country implements PersistablePayload {
public final String code;
public final String name;
public final Region region;
public Country(String code, String name, Region region) {
this.code = code;
this.name = name;
this.region = region;
}
@Override
public Message toProtoMessage() {
return PB.Country.newBuilder().setCode(code).setName(name)
.setRegion(PB.Region.newBuilder().setCode(region.code).setName(region.name)).build();
}
public static Country fromProto(PB.Country proto) {
return new Country(proto.getCode(),
proto.getName(),
Region.fromProto(proto.getRegion()));
}
}

View File

@ -1,476 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import io.bisq.common.GlobalSettings;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
public class CountryUtil {
public static List<Country> getAllSepaEuroCountries() {
List<Country> list = new ArrayList<>();
String[] codes = {"AT", "BE", "CY", "DE", "EE", "FI", "FR", "GR", "IE",
"IT", "LV", "LT", "LU", "MC", "MT", "NL", "PT", "SK", "SI", "ES"};
populateCountryListByCodes(list, codes);
list.sort((a, b) -> a.name.compareTo(b.name));
return list;
}
public static List<Country> getAllSepaInstantEuroCountries() {
return getAllSepaEuroCountries();
}
private static void populateCountryListByCodes(List<Country> list, String[] codes) {
for (String code : codes) {
Locale locale = new Locale(LanguageUtil.getDefaultLanguage(), code, "");
final String countryCode = locale.getCountry();
String regionCode = getRegionCode(countryCode);
final Region region = new Region(regionCode, getRegionName(regionCode));
Country country = new Country(countryCode, locale.getDisplayCountry(), region);
if (countryCode.equals("XK"))
country = new Country(countryCode, getNameByCode(countryCode), region);
list.add(country);
}
}
public static boolean containsAllSepaEuroCountries(List<String> countryCodesToCompare) {
countryCodesToCompare.sort(String::compareTo);
List<String> countryCodesBase = getAllSepaEuroCountries().stream().map(c -> c.code).collect(Collectors.toList());
return countryCodesToCompare.toString().equals(countryCodesBase.toString());
}
public static boolean containsAllSepaInstantEuroCountries(List<String> countryCodesToCompare) {
return containsAllSepaEuroCountries(countryCodesToCompare);
}
public static List<Country> getAllSepaNonEuroCountries() {
List<Country> list = new ArrayList<>();
String[] codes = {"BG", "HR", "CZ", "DK", "GB", "HU", "PL", "RO",
"SE", "IS", "NO", "LI", "CH"};
populateCountryListByCodes(list, codes);
list.sort((a, b) -> a.name.compareTo(b.name));
return list;
}
public static List<Country> getAllSepaInstantNonEuroCountries() {
return getAllSepaNonEuroCountries();
}
public static List<Country> getAllSepaCountries() {
List<Country> list = new ArrayList<>();
list.addAll(getAllSepaEuroCountries());
list.addAll(getAllSepaNonEuroCountries());
return list;
}
public static List<Country> getAllSepaInstantCountries() {
// TODO find reliable source for list
// //Austria, Estonia, Germany, Italy, Latvia, Lithuania, the Netherlands and Spain.
/* List<Country> list = new ArrayList<>();
String[] codes = {"AT", "DE", "EE",
"IT", "LV", "LT", "NL", "ES"};
populateCountryListByCodes(list, codes);
list.sort((a, b) -> a.name.compareTo(b.name));*/
return getAllSepaCountries();
}
public static Country getDefaultCountry() {
String regionCode = getRegionCode(getLocale().getCountry());
final Region region = new Region(regionCode, getRegionName(regionCode));
return new Country(getLocale().getCountry(), getLocale().getDisplayCountry(), region);
}
public static Optional<Country> findCountryByCode(String countryCode) {
return getAllCountries().stream().filter(e -> e.code.equals(countryCode)).findAny();
}
public static String getNameByCode(String countryCode) {
if (countryCode.equals("XK"))
return "Republic of Kosovo";
else
return new Locale(LanguageUtil.getDefaultLanguage(), countryCode).getDisplayCountry();
}
public static String getNameAndCode(String countryCode) {
return getNameByCode(countryCode) + " (" + countryCode + ")";
}
public static String getCodesString(List<String> countryCodes) {
return countryCodes.stream().collect(Collectors.joining(", "));
}
public static String getNamesByCodesString(List<String> countryCodes) {
return getNamesByCodes(countryCodes).stream().collect(Collectors.joining(",\n"));
}
public static List<Region> getAllRegions() {
final List<Region> allRegions = new ArrayList<>();
String regionCode = "AM";
Region region = new Region(regionCode, getRegionName(regionCode));
allRegions.add(region);
regionCode = "AF";
region = new Region(regionCode, getRegionName(regionCode));
allRegions.add(region);
regionCode = "EU";
region = new Region(regionCode, getRegionName(regionCode));
allRegions.add(region);
regionCode = "AS";
region = new Region(regionCode, getRegionName(regionCode));
allRegions.add(region);
regionCode = "OC";
region = new Region(regionCode, getRegionName(regionCode));
allRegions.add(region);
return allRegions;
}
public static List<Country> getAllCountriesForRegion(Region selectedRegion) {
return Lists.newArrayList(Collections2.filter(getAllCountries(), country ->
selectedRegion != null && country != null && selectedRegion.equals(country.region)));
}
public static List<Country> getAllCountries() {
final Set<Country> allCountries = new HashSet<>();
for (final Locale locale : getAllCountryLocales()) {
String regionCode = getRegionCode(locale.getCountry());
final Region region = new Region(regionCode, getRegionName(regionCode));
Country country = new Country(locale.getCountry(), locale.getDisplayCountry(), region);
if (locale.getCountry().equals("XK"))
country = new Country(locale.getCountry(), "Republic of Kosovo", region);
allCountries.add(country);
}
allCountries.add(new Country("GE", "Georgia", new Region("AS", getRegionName("AS"))));
allCountries.add(new Country("BW", "Botswana", new Region("AF", getRegionName("AF"))));
allCountries.add(new Country("IR", "Iran", new Region("AS", getRegionName("AS"))));
final List<Country> allCountriesList = new ArrayList<>(allCountries);
allCountriesList.sort((locale1, locale2) -> locale1.name.compareTo(locale2.name));
return allCountriesList;
}
private static List<Locale> getAllCountryLocales() {
List<Locale> allLocales = LocaleUtil.getAllLocales();
// Filter duplicate locale entries
Set<Locale> allLocalesAsSet = allLocales.stream().filter(locale -> !locale.getCountry().isEmpty())
.collect(Collectors.toSet());
List<Locale> allCountryLocales = new ArrayList<>();
allCountryLocales.addAll(allLocalesAsSet);
allCountryLocales.sort((locale1, locale2) -> locale1.getDisplayCountry().compareTo(locale2.getDisplayCountry()));
return allCountryLocales;
}
private static List<String> getNamesByCodes(List<String> countryCodes) {
return countryCodes.stream().map(CountryUtil::getNameByCode).collect(Collectors.toList());
}
private static String getRegionName(final String regionCode) {
return regionCodeToNameMap.get(regionCode);
}
private static final Map<String, String> regionCodeToNameMap = new HashMap<>();
// Key is: ISO 3166 code, value is region code as defined in regionCodeToNameMap
private static final Map<String, String> regionByCountryCodeMap = new HashMap<>();
static {
regionCodeToNameMap.put("AM", "Americas");
regionCodeToNameMap.put("AF", "Africa");
regionCodeToNameMap.put("EU", "Europe");
regionCodeToNameMap.put("AS", "Asia");
regionCodeToNameMap.put("OC", "Oceania");
// Data extracted from https://restcountries.eu/rest/v2/all?fields=name;region;subregion;alpha2Code;languages
regionByCountryCodeMap.put("AF", "AS"); // name=Afghanistan / region=Asia / subregion=Southern Asia
regionByCountryCodeMap.put("AX", "EU"); // name=Åland Islands / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("AL", "EU"); // name=Albania / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("DZ", "AF"); // name=Algeria / region=Africa / subregion=Northern Africa
regionByCountryCodeMap.put("AS", "OC"); // name=American Samoa / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("AD", "EU"); // name=Andorra / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("AO", "AF"); // name=Angola / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("AI", "AM"); // name=Anguilla / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("AG", "AM"); // name=Antigua and Barbuda / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("AR", "AM"); // name=Argentina / region=Americas / subregion=South America
regionByCountryCodeMap.put("AM", "AS"); // name=Armenia / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("AW", "AM"); // name=Aruba / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("AU", "OC"); // name=Australia / region=Oceania / subregion=Australia and New Zealand
regionByCountryCodeMap.put("AT", "EU"); // name=Austria / region=Europe / subregion=Western Europe
regionByCountryCodeMap.put("AZ", "AS"); // name=Azerbaijan / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("BS", "AM"); // name=Bahamas / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("BH", "AS"); // name=Bahrain / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("BD", "AS"); // name=Bangladesh / region=Asia / subregion=Southern Asia
regionByCountryCodeMap.put("BB", "AM"); // name=Barbados / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("BY", "EU"); // name=Belarus / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("BE", "EU"); // name=Belgium / region=Europe / subregion=Western Europe
regionByCountryCodeMap.put("BZ", "AM"); // name=Belize / region=Americas / subregion=Central America
regionByCountryCodeMap.put("BJ", "AF"); // name=Benin / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("BM", "AM"); // name=Bermuda / region=Americas / subregion=Northern America
regionByCountryCodeMap.put("BT", "AS"); // name=Bhutan / region=Asia / subregion=Southern Asia
regionByCountryCodeMap.put("BO", "AM"); // name=Bolivia (Plurinational State of) / region=Americas / subregion=South America
regionByCountryCodeMap.put("BQ", "AM"); // name=Bonaire, Sint Eustatius and Saba / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("BA", "EU"); // name=Bosnia and Herzegovina / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("BW", "AF"); // name=Botswana / region=Africa / subregion=Southern Africa
regionByCountryCodeMap.put("BR", "AM"); // name=Brazil / region=Americas / subregion=South America
regionByCountryCodeMap.put("IO", "AF"); // name=British Indian Ocean Territory / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("UM", "AM"); // name=United States Minor Outlying Islands / region=Americas / subregion=Northern America
regionByCountryCodeMap.put("VG", "AM"); // name=Virgin Islands (British) / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("VI", "AM"); // name=Virgin Islands (U.S.) / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("BN", "AS"); // name=Brunei Darussalam / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("BG", "EU"); // name=Bulgaria / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("BF", "AF"); // name=Burkina Faso / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("BI", "AF"); // name=Burundi / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("KH", "AS"); // name=Cambodia / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("CM", "AF"); // name=Cameroon / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("CA", "AM"); // name=Canada / region=Americas / subregion=Northern America
regionByCountryCodeMap.put("CV", "AF"); // name=Cabo Verde / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("KY", "AM"); // name=Cayman Islands / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("CF", "AF"); // name=Central African Republic / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("TD", "AF"); // name=Chad / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("CL", "AM"); // name=Chile / region=Americas / subregion=South America
regionByCountryCodeMap.put("CN", "AS"); // name=China / region=Asia / subregion=Eastern Asia
regionByCountryCodeMap.put("CX", "OC"); // name=Christmas Island / region=Oceania / subregion=Australia and New Zealand
regionByCountryCodeMap.put("CC", "OC"); // name=Cocos (Keeling) Islands / region=Oceania / subregion=Australia and New Zealand
regionByCountryCodeMap.put("CO", "AM"); // name=Colombia / region=Americas / subregion=South America
regionByCountryCodeMap.put("KM", "AF"); // name=Comoros / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("CG", "AF"); // name=Congo / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("CD", "AF"); // name=Congo (Democratic Republic of the) / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("CK", "OC"); // name=Cook Islands / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("CR", "AM"); // name=Costa Rica / region=Americas / subregion=Central America
regionByCountryCodeMap.put("HR", "EU"); // name=Croatia / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("CU", "AM"); // name=Cuba / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("CW", "AM"); // name=Curaçao / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("CY", "EU"); // name=Cyprus / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("CZ", "EU"); // name=Czech Republic / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("DK", "EU"); // name=Denmark / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("DJ", "AF"); // name=Djibouti / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("DM", "AM"); // name=Dominica / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("DO", "AM"); // name=Dominican Republic / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("EC", "AM"); // name=Ecuador / region=Americas / subregion=South America
regionByCountryCodeMap.put("EG", "AF"); // name=Egypt / region=Africa / subregion=Northern Africa
regionByCountryCodeMap.put("SV", "AM"); // name=El Salvador / region=Americas / subregion=Central America
regionByCountryCodeMap.put("GQ", "AF"); // name=Equatorial Guinea / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("ER", "AF"); // name=Eritrea / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("EE", "EU"); // name=Estonia / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("ET", "AF"); // name=Ethiopia / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("FK", "AM"); // name=Falkland Islands (Malvinas) / region=Americas / subregion=South America
regionByCountryCodeMap.put("FO", "EU"); // name=Faroe Islands / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("FJ", "OC"); // name=Fiji / region=Oceania / subregion=Melanesia
regionByCountryCodeMap.put("FI", "EU"); // name=Finland / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("FR", "EU"); // name=France / region=Europe / subregion=Western Europe
regionByCountryCodeMap.put("GF", "AM"); // name=French Guiana / region=Americas / subregion=South America
regionByCountryCodeMap.put("PF", "OC"); // name=French Polynesia / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("TF", "AF"); // name=French Southern Territories / region=Africa / subregion=Southern Africa
regionByCountryCodeMap.put("GA", "AF"); // name=Gabon / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("GM", "AF"); // name=Gambia / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("GE", "AS"); // name=Georgia / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("DE", "EU"); // name=Germany / region=Europe / subregion=Western Europe
regionByCountryCodeMap.put("GH", "AF"); // name=Ghana / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("GI", "EU"); // name=Gibraltar / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("GR", "EU"); // name=Greece / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("GL", "AM"); // name=Greenland / region=Americas / subregion=Northern America
regionByCountryCodeMap.put("GD", "AM"); // name=Grenada / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("GP", "AM"); // name=Guadeloupe / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("GU", "OC"); // name=Guam / region=Oceania / subregion=Micronesia
regionByCountryCodeMap.put("GT", "AM"); // name=Guatemala / region=Americas / subregion=Central America
regionByCountryCodeMap.put("GG", "EU"); // name=Guernsey / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("GN", "AF"); // name=Guinea / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("GW", "AF"); // name=Guinea-Bissau / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("GY", "AM"); // name=Guyana / region=Americas / subregion=South America
regionByCountryCodeMap.put("HT", "AM"); // name=Haiti / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("VA", "EU"); // name=Holy See / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("HN", "AM"); // name=Honduras / region=Americas / subregion=Central America
regionByCountryCodeMap.put("HK", "AS"); // name=Hong Kong / region=Asia / subregion=Eastern Asia
regionByCountryCodeMap.put("HU", "EU"); // name=Hungary / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("IS", "EU"); // name=Iceland / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("IN", "AS"); // name=India / region=Asia / subregion=Southern Asia
regionByCountryCodeMap.put("ID", "AS"); // name=Indonesia / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("CI", "AF"); // name=Côte d'Ivoire / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("IR", "AS"); // name=Iran (Islamic Republic of) / region=Asia / subregion=Southern Asia
regionByCountryCodeMap.put("IQ", "AS"); // name=Iraq / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("IE", "EU"); // name=Ireland / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("IM", "EU"); // name=Isle of Man / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("IL", "AS"); // name=Israel / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("IT", "EU"); // name=Italy / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("JM", "AM"); // name=Jamaica / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("JP", "AS"); // name=Japan / region=Asia / subregion=Eastern Asia
regionByCountryCodeMap.put("JE", "EU"); // name=Jersey / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("JO", "AS"); // name=Jordan / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("KZ", "AS"); // name=Kazakhstan / region=Asia / subregion=Central Asia
regionByCountryCodeMap.put("KE", "AF"); // name=Kenya / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("KI", "OC"); // name=Kiribati / region=Oceania / subregion=Micronesia
regionByCountryCodeMap.put("KW", "AS"); // name=Kuwait / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("KG", "AS"); // name=Kyrgyzstan / region=Asia / subregion=Central Asia
regionByCountryCodeMap.put("LA", "AS"); // name=Lao People's Democratic Republic / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("LV", "EU"); // name=Latvia / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("LB", "AS"); // name=Lebanon / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("LS", "AF"); // name=Lesotho / region=Africa / subregion=Southern Africa
regionByCountryCodeMap.put("LR", "AF"); // name=Liberia / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("LY", "AF"); // name=Libya / region=Africa / subregion=Northern Africa
regionByCountryCodeMap.put("LI", "EU"); // name=Liechtenstein / region=Europe / subregion=Western Europe
regionByCountryCodeMap.put("LT", "EU"); // name=Lithuania / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("LU", "EU"); // name=Luxembourg / region=Europe / subregion=Western Europe
regionByCountryCodeMap.put("MO", "AS"); // name=Macao / region=Asia / subregion=Eastern Asia
regionByCountryCodeMap.put("MK", "EU"); // name=Macedonia (the former Yugoslav Republic of) / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("MG", "AF"); // name=Madagascar / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("MW", "AF"); // name=Malawi / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("MY", "AS"); // name=Malaysia / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("MV", "AS"); // name=Maldives / region=Asia / subregion=Southern Asia
regionByCountryCodeMap.put("ML", "AF"); // name=Mali / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("MT", "EU"); // name=Malta / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("MH", "OC"); // name=Marshall Islands / region=Oceania / subregion=Micronesia
regionByCountryCodeMap.put("MQ", "AM"); // name=Martinique / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("MR", "AF"); // name=Mauritania / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("MU", "AF"); // name=Mauritius / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("YT", "AF"); // name=Mayotte / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("MX", "AM"); // name=Mexico / region=Americas / subregion=Central America
regionByCountryCodeMap.put("FM", "OC"); // name=Micronesia (Federated States of) / region=Oceania / subregion=Micronesia
regionByCountryCodeMap.put("MD", "EU"); // name=Moldova (Republic of) / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("MC", "EU"); // name=Monaco / region=Europe / subregion=Western Europe
regionByCountryCodeMap.put("MN", "AS"); // name=Mongolia / region=Asia / subregion=Eastern Asia
regionByCountryCodeMap.put("ME", "EU"); // name=Montenegro / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("MS", "AM"); // name=Montserrat / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("MA", "AF"); // name=Morocco / region=Africa / subregion=Northern Africa
regionByCountryCodeMap.put("MZ", "AF"); // name=Mozambique / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("MM", "AS"); // name=Myanmar / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("NA", "AF"); // name=Namibia / region=Africa / subregion=Southern Africa
regionByCountryCodeMap.put("NR", "OC"); // name=Nauru / region=Oceania / subregion=Micronesia
regionByCountryCodeMap.put("NP", "AS"); // name=Nepal / region=Asia / subregion=Southern Asia
regionByCountryCodeMap.put("NL", "EU"); // name=Netherlands / region=Europe / subregion=Western Europe
regionByCountryCodeMap.put("NC", "OC"); // name=New Caledonia / region=Oceania / subregion=Melanesia
regionByCountryCodeMap.put("NZ", "OC"); // name=New Zealand / region=Oceania / subregion=Australia and New Zealand
regionByCountryCodeMap.put("NI", "AM"); // name=Nicaragua / region=Americas / subregion=Central America
regionByCountryCodeMap.put("NE", "AF"); // name=Niger / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("NG", "AF"); // name=Nigeria / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("NU", "OC"); // name=Niue / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("NF", "OC"); // name=Norfolk Island / region=Oceania / subregion=Australia and New Zealand
regionByCountryCodeMap.put("KP", "AS"); // name=Korea (Democratic People's Republic of) / region=Asia / subregion=Eastern Asia
regionByCountryCodeMap.put("MP", "OC"); // name=Northern Mariana Islands / region=Oceania / subregion=Micronesia
regionByCountryCodeMap.put("NO", "EU"); // name=Norway / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("OM", "AS"); // name=Oman / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("PK", "AS"); // name=Pakistan / region=Asia / subregion=Southern Asia
regionByCountryCodeMap.put("PW", "OC"); // name=Palau / region=Oceania / subregion=Micronesia
regionByCountryCodeMap.put("PS", "AS"); // name=Palestine, State of / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("PA", "AM"); // name=Panama / region=Americas / subregion=Central America
regionByCountryCodeMap.put("PG", "OC"); // name=Papua New Guinea / region=Oceania / subregion=Melanesia
regionByCountryCodeMap.put("PY", "AM"); // name=Paraguay / region=Americas / subregion=South America
regionByCountryCodeMap.put("PE", "AM"); // name=Peru / region=Americas / subregion=South America
regionByCountryCodeMap.put("PH", "AS"); // name=Philippines / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("PN", "OC"); // name=Pitcairn / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("PL", "EU"); // name=Poland / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("PT", "EU"); // name=Portugal / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("PR", "AM"); // name=Puerto Rico / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("QA", "AS"); // name=Qatar / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("XK", "EU"); // name=Republic of Kosovo / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("RE", "AF"); // name=Réunion / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("RO", "EU"); // name=Romania / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("RU", "EU"); // name=Russian Federation / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("RW", "AF"); // name=Rwanda / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("BL", "AM"); // name=Saint Barthélemy / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("SH", "AF"); // name=Saint Helena, Ascension and Tristan da Cunha / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("KN", "AM"); // name=Saint Kitts and Nevis / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("LC", "AM"); // name=Saint Lucia / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("MF", "AM"); // name=Saint Martin (French part) / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("PM", "AM"); // name=Saint Pierre and Miquelon / region=Americas / subregion=Northern America
regionByCountryCodeMap.put("VC", "AM"); // name=Saint Vincent and the Grenadines / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("WS", "OC"); // name=Samoa / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("SM", "EU"); // name=San Marino / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("ST", "AF"); // name=Sao Tome and Principe / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("SA", "AS"); // name=Saudi Arabia / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("SN", "AF"); // name=Senegal / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("RS", "EU"); // name=Serbia / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("SC", "AF"); // name=Seychelles / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("SL", "AF"); // name=Sierra Leone / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("SG", "AS"); // name=Singapore / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("SX", "AM"); // name=Sint Maarten (Dutch part) / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("SK", "EU"); // name=Slovakia / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("SI", "EU"); // name=Slovenia / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("SB", "OC"); // name=Solomon Islands / region=Oceania / subregion=Melanesia
regionByCountryCodeMap.put("SO", "AF"); // name=Somalia / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("ZA", "AF"); // name=South Africa / region=Africa / subregion=Southern Africa
regionByCountryCodeMap.put("GS", "AM"); // name=South Georgia and the South Sandwich Islands / region=Americas / subregion=South America
regionByCountryCodeMap.put("KR", "AS"); // name=Korea (Republic of) / region=Asia / subregion=Eastern Asia
regionByCountryCodeMap.put("SS", "AF"); // name=South Sudan / region=Africa / subregion=Middle Africa
regionByCountryCodeMap.put("ES", "EU"); // name=Spain / region=Europe / subregion=Southern Europe
regionByCountryCodeMap.put("LK", "AS"); // name=Sri Lanka / region=Asia / subregion=Southern Asia
regionByCountryCodeMap.put("SD", "AF"); // name=Sudan / region=Africa / subregion=Northern Africa
regionByCountryCodeMap.put("SR", "AM"); // name=Suriname / region=Americas / subregion=South America
regionByCountryCodeMap.put("SJ", "EU"); // name=Svalbard and Jan Mayen / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("SZ", "AF"); // name=Swaziland / region=Africa / subregion=Southern Africa
regionByCountryCodeMap.put("SE", "EU"); // name=Sweden / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("CH", "EU"); // name=Switzerland / region=Europe / subregion=Western Europe
regionByCountryCodeMap.put("SY", "AS"); // name=Syrian Arab Republic / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("TW", "AS"); // name=Taiwan / region=Asia / subregion=Eastern Asia
regionByCountryCodeMap.put("TJ", "AS"); // name=Tajikistan / region=Asia / subregion=Central Asia
regionByCountryCodeMap.put("TZ", "AF"); // name=Tanzania, United Republic of / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("TH", "AS"); // name=Thailand / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("TL", "AS"); // name=Timor-Leste / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("TG", "AF"); // name=Togo / region=Africa / subregion=Western Africa
regionByCountryCodeMap.put("TK", "OC"); // name=Tokelau / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("TO", "OC"); // name=Tonga / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("TT", "AM"); // name=Trinidad and Tobago / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("TN", "AF"); // name=Tunisia / region=Africa / subregion=Northern Africa
regionByCountryCodeMap.put("TR", "AS"); // name=Turkey / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("TM", "AS"); // name=Turkmenistan / region=Asia / subregion=Central Asia
regionByCountryCodeMap.put("TC", "AM"); // name=Turks and Caicos Islands / region=Americas / subregion=Caribbean
regionByCountryCodeMap.put("TV", "OC"); // name=Tuvalu / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("UG", "AF"); // name=Uganda / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("UA", "EU"); // name=Ukraine / region=Europe / subregion=Eastern Europe
regionByCountryCodeMap.put("AE", "AS"); // name=United Arab Emirates / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("GB", "EU"); // name=United Kingdom of Great Britain and Northern Ireland / region=Europe / subregion=Northern Europe
regionByCountryCodeMap.put("US", "AM"); // name=United States of America / region=Americas / subregion=Northern America
regionByCountryCodeMap.put("UY", "AM"); // name=Uruguay / region=Americas / subregion=South America
regionByCountryCodeMap.put("UZ", "AS"); // name=Uzbekistan / region=Asia / subregion=Central Asia
regionByCountryCodeMap.put("VU", "OC"); // name=Vanuatu / region=Oceania / subregion=Melanesia
regionByCountryCodeMap.put("VE", "AM"); // name=Venezuela (Bolivarian Republic of) / region=Americas / subregion=South America
regionByCountryCodeMap.put("VN", "AS"); // name=Viet Nam / region=Asia / subregion=South-Eastern Asia
regionByCountryCodeMap.put("WF", "OC"); // name=Wallis and Futuna / region=Oceania / subregion=Polynesia
regionByCountryCodeMap.put("EH", "AF"); // name=Western Sahara / region=Africa / subregion=Northern Africa
regionByCountryCodeMap.put("YE", "AS"); // name=Yemen / region=Asia / subregion=Western Asia
regionByCountryCodeMap.put("ZM", "AF"); // name=Zambia / region=Africa / subregion=Eastern Africa
regionByCountryCodeMap.put("ZW", "AF"); // name=Zimbabwe / region=Africa / subregion=Eastern Africa
}
public static String getRegionCode(String countryCode) {
if (regionByCountryCodeMap.containsKey(countryCode))
return regionByCountryCodeMap.get(countryCode);
else
return "Undefined";
}
public static String getDefaultCountryCode() {
// might be set later in pref or config, so not use Preferences.getDefaultLocale() anywhere in the code
return getLocale().getCountry();
}
private static Locale getLocale() {
return GlobalSettings.getLocale();
}
}

View File

@ -1,73 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import com.google.protobuf.Message;
import io.bisq.generated.protobuffer.PB;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@EqualsAndHashCode(callSuper = true)
public final class CryptoCurrency extends TradeCurrency {
// http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618
private final static String PREFIX = "";
@Getter
private boolean isAsset = false;
public CryptoCurrency(String currencyCode,
String name) {
this(currencyCode, name, false);
}
public CryptoCurrency(String currencyCode,
String name,
boolean isAsset) {
super(currencyCode, name);
this.isAsset = isAsset;
}
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public Message toProtoMessage() {
return getTradeCurrencyBuilder()
.setCryptoCurrency(PB.CryptoCurrency.newBuilder()
.setIsAsset(isAsset))
.build();
}
public static CryptoCurrency fromProto(PB.TradeCurrency proto) {
return new CryptoCurrency(proto.getCode(),
proto.getName(),
proto.getCryptoCurrency().getIsAsset());
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public String getDisplayPrefix() {
return PREFIX;
}
}

View File

@ -1,39 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode
public class CurrencyTuple {
public final String code;
public final String name;
public final int precision; // precision 4 is 1/10000 -> 0.0001 is smallest unit
public CurrencyTuple(String code, String name) {
// We use Fiat class and there precision is 4
// In future we might add custom precision per currency
this(code, name, 4);
}
public CurrencyTuple(String code, String name, int precision) {
this.code = code;
this.name = name;
this.precision = precision;
}
}

View File

@ -1,390 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import io.bisq.common.GlobalSettings;
import io.bisq.common.app.DevEnv;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
public class CurrencyUtil {
private static String baseCurrencyCode = "BTC";
public static void setBaseCurrencyCode(String baseCurrencyCode) {
CurrencyUtil.baseCurrencyCode = baseCurrencyCode;
}
private static List<FiatCurrency> allSortedFiatCurrencies;
private static List<FiatCurrency> createAllSortedFiatCurrenciesList() {
Set<FiatCurrency> set = CountryUtil.getAllCountries().stream()
.map(country -> getCurrencyByCountryCode(country.code))
.collect(Collectors.toSet());
List<FiatCurrency> list = new ArrayList<>(set);
list.sort(TradeCurrency::compareTo);
return list;
}
public static List<FiatCurrency> getAllSortedFiatCurrencies() {
if (Objects.isNull(allSortedFiatCurrencies)) {
allSortedFiatCurrencies = createAllSortedFiatCurrenciesList();
}
return allSortedFiatCurrencies;
}
public static List<FiatCurrency> getMainFiatCurrencies() {
TradeCurrency defaultTradeCurrency = getDefaultTradeCurrency();
List<FiatCurrency> list = new ArrayList<>();
// Top traded currencies
list.add(new FiatCurrency("USD"));
list.add(new FiatCurrency("EUR"));
list.add(new FiatCurrency("GBP"));
list.add(new FiatCurrency("CAD"));
list.add(new FiatCurrency("AUD"));
list.add(new FiatCurrency("RUB"));
list.add(new FiatCurrency("INR"));
list.sort(TradeCurrency::compareTo);
FiatCurrency defaultFiatCurrency = defaultTradeCurrency instanceof FiatCurrency ? (FiatCurrency) defaultTradeCurrency : null;
if (defaultFiatCurrency != null && list.contains(defaultFiatCurrency)) {
//noinspection SuspiciousMethodCalls
list.remove(defaultTradeCurrency);
list.add(0, defaultFiatCurrency);
}
return list;
}
private static List<CryptoCurrency> allSortedCryptoCurrencies;
public static List<CryptoCurrency> getAllSortedCryptoCurrencies() {
if (allSortedCryptoCurrencies == null)
allSortedCryptoCurrencies = createAllSortedCryptoCurrenciesList();
return allSortedCryptoCurrencies;
}
// Don't make a PR for adding a coin but follow the steps described here:
// https://forum.bisq.network/t/how-to-add-your-favorite-altcoin/
public static List<CryptoCurrency> createAllSortedCryptoCurrenciesList() {
final List<CryptoCurrency> result = new ArrayList<>();
result.add(new CryptoCurrency("BETR", "Better Betting", true));
if (DevEnv.DAO_TRADING_ACTIVATED)
result.add(new CryptoCurrency("BSQ", "Bisq Token"));
if (!baseCurrencyCode.equals("BTC"))
result.add(new CryptoCurrency("BTC", "Bitcoin"));
result.add(new CryptoCurrency("BCH", "Bitcoin Cash"));
result.add(new CryptoCurrency("BCHC", "Bitcoin Clashic"));
result.add(new CryptoCurrency("BTG", "Bitcoin Gold"));
result.add(new CryptoCurrency("BURST", "Burstcoin"));
result.add(new CryptoCurrency("GBYTE", "Byte"));
result.add(new CryptoCurrency("CAGE", "Cagecoin"));
result.add(new CryptoCurrency("XCP", "Counterparty"));
result.add(new CryptoCurrency("CREA", "Creativecoin"));
result.add(new CryptoCurrency("XCN", "Cryptonite"));
result.add(new CryptoCurrency("DNET", "DarkNet"));
if (!baseCurrencyCode.equals("DASH"))
result.add(new CryptoCurrency("DASH", "Dash"));
result.add(new CryptoCurrency("DCT", "DECENT"));
result.add(new CryptoCurrency("DCR", "Decred"));
result.add(new CryptoCurrency("ONION", "DeepOnion"));
result.add(new CryptoCurrency("DOGE", "Dogecoin"));
result.add(new CryptoCurrency("DMC", "DynamicCoin"));
result.add(new CryptoCurrency("ELLA", "Ellaism"));
result.add(new CryptoCurrency("ESP", "Espers"));
result.add(new CryptoCurrency("ETH", "Ether"));
result.add(new CryptoCurrency("ETC", "Ether Classic"));
result.add(new CryptoCurrency("XIN", "Infinity Economics"));
result.add(new CryptoCurrency("IOP", "Internet Of People"));
result.add(new CryptoCurrency("INXT", "Internext", true));
result.add(new CryptoCurrency("GRC", "Gridcoin"));
result.add(new CryptoCurrency("LBC", "LBRY Credits"));
result.add(new CryptoCurrency("LSK", "Lisk"));
if (!baseCurrencyCode.equals("LTC"))
result.add(new CryptoCurrency("LTC", "Litecoin"));
result.add(new CryptoCurrency("MAID", "MaidSafeCoin"));
result.add(new CryptoCurrency("MDC", "Madcoin"));
result.add(new CryptoCurrency("XMR", "Monero"));
result.add(new CryptoCurrency("MT", "Mycelium Token", true));
result.add(new CryptoCurrency("NAV", "Nav Coin"));
result.add(new CryptoCurrency("NMC", "Namecoin"));
result.add(new CryptoCurrency("NBT", "NuBits"));
result.add(new CryptoCurrency("NXT", "Nxt"));
result.add(new CryptoCurrency("888", "OctoCoin"));
result.add(new CryptoCurrency("PART", "Particl"));
result.add(new CryptoCurrency("PASC", "Pascal Coin", true));
result.add(new CryptoCurrency("PEPECASH", "Pepe Cash"));
result.add(new CryptoCurrency("PIVX", "PIVX"));
result.add(new CryptoCurrency("POST", "PostCoin"));
result.add(new CryptoCurrency("PNC", "Pranacoin"));
result.add(new CryptoCurrency("RDD", "ReddCoin"));
result.add(new CryptoCurrency("REF", "RefToken", true));
result.add(new CryptoCurrency("SFSC", "Safe FileSystem Coin"));
result.add(new CryptoCurrency("SC", "Siacoin"));
result.add(new CryptoCurrency("SF", "Siafund"));
result.add(new CryptoCurrency("SIB", "Sibcoin"));
result.add(new CryptoCurrency("XSPEC", "Spectrecoin"));
result.add(new CryptoCurrency("STEEM", "STEEM"));
result.add(new CryptoCurrency("TRC", "Terracoin"));
result.add(new CryptoCurrency("MVT", "The Movement", true));
result.add(new CryptoCurrency("UNO", "Unobtanium"));
result.add(new CryptoCurrency("CRED", "Verify", true));
result.add(new CryptoCurrency("WAC", "WACoins"));
result.add(new CryptoCurrency("WILD", "WILD Token", true));
result.add(new CryptoCurrency("XZC", "Zcoin"));
result.add(new CryptoCurrency("ZEC", "Zcash"));
result.add(new CryptoCurrency("ZEN", "ZenCash"));
// Added 0.6.6
result.add(new CryptoCurrency("STL", "Stellite"));
result.add(new CryptoCurrency("DAI", "Dai Stablecoin", true));
result.add(new CryptoCurrency("YTN", "Yenten"));
result.add(new CryptoCurrency("DARX", "BitDaric"));
result.add(new CryptoCurrency("ODN", "Obsidian"));
result.add(new CryptoCurrency("CDT", "Cassubian Detk"));
result.add(new CryptoCurrency("DGM", "DigiMoney"));
result.add(new CryptoCurrency("SCS", "SpeedCash"));
result.add(new CryptoCurrency("SOS", "SOS Coin", true));
result.add(new CryptoCurrency("ACH", "AchieveCoin"));
result.add(new CryptoCurrency("VDN", "vDinar"));
result.add(new CryptoCurrency("WMCC", "WorldMobileCoin"));
// Added 0.7.0
result.add(new CryptoCurrency("ALC", "Angelcoin"));
result.add(new CryptoCurrency("DIN", "Dinero"));
result.add(new CryptoCurrency("NAH", "Strayacoin"));
result.add(new CryptoCurrency("ROI", "ROIcoin"));
result.sort(TradeCurrency::compareTo);
// Util for printing all altcoins for adding to FAQ page
/* StringBuilder sb = new StringBuilder();
result.stream().forEach(e -> sb.append("<li>&#8220;")
.append(e.getCode())
.append("&#8221;, &#8220;")
.append(e.getName())
.append("&#8221;</li>")
.append("\n"));
log.info(sb.toString());*/
return result;
}
public static List<CryptoCurrency> getMainCryptoCurrencies() {
final List<CryptoCurrency> result = new ArrayList<>();
if (DevEnv.DAO_TRADING_ACTIVATED)
result.add(new CryptoCurrency("BSQ", "Bisq Token"));
if (!baseCurrencyCode.equals("BTC"))
result.add(new CryptoCurrency("BTC", "Bitcoin"));
if (!baseCurrencyCode.equals("DASH"))
result.add(new CryptoCurrency("DASH", "Dash"));
result.add(new CryptoCurrency("DCR", "Decred"));
result.add(new CryptoCurrency("ONION", "DeepOnion"));
result.add(new CryptoCurrency("ETH", "Ether"));
result.add(new CryptoCurrency("ETC", "Ether Classic"));
result.add(new CryptoCurrency("GRC", "Gridcoin"));
if (!baseCurrencyCode.equals("LTC"))
result.add(new CryptoCurrency("LTC", "Litecoin"));
result.add(new CryptoCurrency("XMR", "Monero"));
result.add(new CryptoCurrency("MT", "Mycelium Token", true));
result.add(new CryptoCurrency("NMC", "Namecoin"));
result.add(new CryptoCurrency("SC", "Siacoin"));
result.add(new CryptoCurrency("SF", "Siafund"));
result.add(new CryptoCurrency("UNO", "Unobtanium"));
result.add(new CryptoCurrency("ZEC", "Zcash"));
result.sort(TradeCurrency::compareTo);
return result;
}
/**
* @return Sorted list of SEPA currencies with EUR as first item
*/
private static Set<TradeCurrency> getSortedSEPACurrencyCodes() {
return CountryUtil.getAllSepaCountries().stream()
.map(country -> getCurrencyByCountryCode(country.code))
.collect(Collectors.toSet());
}
// At OKPay you can exchange internally those currencies
public static List<TradeCurrency> getAllOKPayCurrencies() {
ArrayList<TradeCurrency> currencies = new ArrayList<>(Arrays.asList(
new FiatCurrency("EUR"),
new FiatCurrency("USD"),
new FiatCurrency("GBP"),
new FiatCurrency("CHF"),
new FiatCurrency("RUB"),
new FiatCurrency("PLN"),
new FiatCurrency("JPY"),
new FiatCurrency("CAD"),
new FiatCurrency("AUD"),
new FiatCurrency("CZK"),
new FiatCurrency("NOK"),
new FiatCurrency("SEK"),
new FiatCurrency("DKK"),
new FiatCurrency("HRK"),
new FiatCurrency("HUF"),
new FiatCurrency("NZD"),
new FiatCurrency("RON"),
new FiatCurrency("TRY"),
new FiatCurrency("ZAR"),
new FiatCurrency("HKD"),
new FiatCurrency("CNY")
));
currencies.sort(Comparator.comparing(TradeCurrency::getCode));
return currencies;
}
// https://support.uphold.com/hc/en-us/articles/202473803-Supported-currencies
public static List<TradeCurrency> getAllUpholdCurrencies() {
ArrayList<TradeCurrency> currencies = new ArrayList<>(Arrays.asList(
new FiatCurrency("USD"),
new FiatCurrency("EUR"),
new FiatCurrency("GBP"),
new FiatCurrency("CNY"),
new FiatCurrency("JPY"),
new FiatCurrency("CHF"),
new FiatCurrency("INR"),
new FiatCurrency("MXN"),
new FiatCurrency("AUD"),
new FiatCurrency("CAD"),
new FiatCurrency("HKD"),
new FiatCurrency("NZD"),
new FiatCurrency("SGD"),
new FiatCurrency("KES"),
new FiatCurrency("ILS"),
new FiatCurrency("DKK"),
new FiatCurrency("NOK"),
new FiatCurrency("SEK"),
new FiatCurrency("PLN"),
new FiatCurrency("ARS"),
new FiatCurrency("BRL"),
new FiatCurrency("AED"),
new FiatCurrency("PHP")
));
currencies.sort(Comparator.comparing(TradeCurrency::getCode));
return currencies;
}
//https://www.revolut.com/pa/faq#can-i-hold-multiple-currencies
public static List<TradeCurrency> getAllRevolutCurrencies() {
ArrayList<TradeCurrency> currencies = new ArrayList<>(Arrays.asList(
new FiatCurrency("USD"),
new FiatCurrency("GBP"),
new FiatCurrency("EUR"),
new FiatCurrency("PLN"),
new FiatCurrency("CHF"),
new FiatCurrency("DKK"),
new FiatCurrency("NOK"),
new FiatCurrency("SEK"),
new FiatCurrency("RON"),
new FiatCurrency("SGD"),
new FiatCurrency("HKD"),
new FiatCurrency("AUD"),
new FiatCurrency("NZD"),
new FiatCurrency("TRY"),
new FiatCurrency("ILS"),
new FiatCurrency("AED"),
new FiatCurrency("CAD"),
new FiatCurrency("HUF"),
new FiatCurrency("INR"),
new FiatCurrency("JPY"),
new FiatCurrency("MAD"),
new FiatCurrency("QAR"),
new FiatCurrency("THB"),
new FiatCurrency("ZAR")
));
currencies.sort(Comparator.comparing(TradeCurrency::getCode));
return currencies;
}
public static boolean isFiatCurrency(String currencyCode) {
try {
return currencyCode != null && !currencyCode.isEmpty() && !isCryptoCurrency(currencyCode) && Currency.getInstance(currencyCode) != null;
} catch (Throwable t) {
return false;
}
}
public static Optional<FiatCurrency> getFiatCurrency(String currencyCode) {
return getAllSortedFiatCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findAny();
}
@SuppressWarnings("WeakerAccess")
public static boolean isCryptoCurrency(String currencyCode) {
return getCryptoCurrency(currencyCode).isPresent();
}
public static Optional<CryptoCurrency> getCryptoCurrency(String currencyCode) {
return getAllSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findAny();
}
public static Optional<TradeCurrency> getTradeCurrency(String currencyCode) {
Optional<FiatCurrency> fiatCurrencyOptional = getFiatCurrency(currencyCode);
if (isFiatCurrency(currencyCode) && fiatCurrencyOptional.isPresent()) {
return Optional.of(fiatCurrencyOptional.get());
} else {
Optional<CryptoCurrency> cryptoCurrencyOptional = getCryptoCurrency(currencyCode);
if (isCryptoCurrency(currencyCode) && cryptoCurrencyOptional.isPresent()) {
return Optional.of(cryptoCurrencyOptional.get());
} else {
return Optional.<TradeCurrency>empty();
}
}
}
public static FiatCurrency getCurrencyByCountryCode(String countryCode) {
if (countryCode.equals("XK"))
return new FiatCurrency("EUR");
else
return new FiatCurrency(Currency.getInstance(new Locale(LanguageUtil.getDefaultLanguage(), countryCode)).getCurrencyCode());
}
public static String getNameByCode(String currencyCode) {
if (isCryptoCurrency(currencyCode))
return getCryptoCurrency(currencyCode).get().getName();
else
try {
return Currency.getInstance(currencyCode).getDisplayName();
} catch (Throwable t) {
log.debug("No currency name available " + t.getMessage());
return currencyCode;
}
}
public static String getNameAndCode(String currencyCode) {
return getNameByCode(currencyCode) + " (" + currencyCode + ")";
}
public static TradeCurrency getDefaultTradeCurrency() {
return GlobalSettings.getDefaultTradeCurrency();
}
}

View File

@ -1,86 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import com.google.protobuf.Message;
import io.bisq.common.GlobalSettings;
import io.bisq.generated.protobuffer.PB;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import java.util.Currency;
import java.util.Locale;
@EqualsAndHashCode(callSuper = true)
@ToString
@Getter
public final class FiatCurrency extends TradeCurrency {
// http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618
private final static String PREFIX = "";
private final Currency currency;
public FiatCurrency(String currencyCode) {
this(Currency.getInstance(currencyCode), getLocale());
}
@SuppressWarnings("WeakerAccess")
public FiatCurrency(Currency currency) {
this(currency, getLocale());
}
@SuppressWarnings("WeakerAccess")
public FiatCurrency(Currency currency, Locale locale) {
super(currency.getCurrencyCode(), currency.getDisplayName(locale));
this.currency = currency;
}
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public Message toProtoMessage() {
PB.Currency.Builder currencyBuilder = PB.Currency.newBuilder().setCurrencyCode(currency.getCurrencyCode());
PB.FiatCurrency.Builder fiatCurrencyBuilder = PB.FiatCurrency.newBuilder().setCurrency(currencyBuilder);
return getTradeCurrencyBuilder()
.setFiatCurrency(fiatCurrencyBuilder)
.build();
}
public static FiatCurrency fromProto(PB.TradeCurrency proto) {
return new FiatCurrency(proto.getCode());
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
private static Locale getLocale() {
return GlobalSettings.getLocale();
}
@Override
public String getDisplayPrefix() {
return PREFIX;
}
}

View File

@ -1,128 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import io.bisq.common.GlobalSettings;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
public class LanguageUtil {
private static final List<String> userLanguageCodes = Arrays.asList(
"en", // English
"de", // German
"el", // Greek
"es", // Spanish
"pt", // Portuguese / Brazil
"sr", // Serbian
"zh", // Chinese
"hu", // Hungarian
"ro", // Romanian
"ru", // Russian
"fr", // French
"tr" // Turkish
/*
// not translated yet
"it", // Italian
"ja", // Japanese
"iw", // Hebrew
"hi", // Hindi
"ko", // Korean
"pl", // Polish
"sv", // Swedish
"no", // Norwegian
"nl", // Dutch
"be", // Belarusian
"fi", // Finnish
"bg", // Bulgarian
"lt", // Lithuanian
"lv", // Latvian
"hr", // Croatian
"uk", // Ukrainian
"sk", // Slovak
"sl", // Slovenian
"ga", // Irish
"sq", // Albanian
"ca", // Catalan
"mk", // Macedonian
"kk", // Kazakh
"km", // Khmer
"sw", // Swahili
"in", // Indonesian
"ms", // Malay
"is", // Icelandic
"et", // Estonian
"cs", // Czech
"ar", // Arabic
"vi", // Vietnamese
"th", // Thai
"da", // Danish
"mt" // Maltese
*/
);
public static List<String> getAllLanguageCodes() {
List<Locale> allLocales = LocaleUtil.getAllLocales();
// Filter duplicate locale entries
Set<String> allLocalesAsSet = allLocales.stream().filter(locale -> !locale.getLanguage().isEmpty() &&
!locale.getDisplayLanguage().isEmpty())
.map(Locale::getLanguage)
.collect(Collectors.toSet());
List<String> allLanguageCodes = new ArrayList<>();
allLanguageCodes.addAll(allLocalesAsSet);
allLanguageCodes.sort((o1, o2) -> getDisplayName(o1).compareTo(getDisplayName(o2)));
return allLanguageCodes;
}
public static String getDefaultLanguage() {
// might be set later in pref or config, so not use defaultLocale anywhere in the code
return getLocale().getLanguage();
}
public static String getDefaultLanguageLocaleAsCode() {
return new Locale(LanguageUtil.getDefaultLanguage(), "").getLanguage();
}
public static String getEnglishLanguageLocaleCode() {
return new Locale(Locale.ENGLISH.getLanguage(), "").getLanguage();
}
public static String getDisplayName(String code) {
Locale locale = new Locale(code.toUpperCase());
if (locale.getLanguage().equals("sr")) {
// Serbia
// shows it in russian by default
return "Srpski";
} else {
return locale.getDisplayName(locale);
}
}
public static List<String> getUserLanguageCodes() {
return userLanguageCodes;
}
private static Locale getLocale() {
return GlobalSettings.getLocale();
}
}

View File

@ -1,285 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class LocaleUtil {
private static final Logger log = LoggerFactory.getLogger(LocaleUtil.class);
public static List<Locale> getAllLocales() {
// Data from https://restcountries.eu/rest/v2/all?fields=name;region;subregion;alpha2Code;languages
List<Locale> allLocales = new ArrayList<>();
allLocales.add(new Locale("ps", "AF")); // Afghanistan / lang=Pashto
allLocales.add(new Locale("sv", "AX")); // Åland Islands / lang=Swedish
allLocales.add(new Locale("sq", "AL")); // Albania / lang=Albanian
allLocales.add(new Locale("ar", "DZ")); // Algeria / lang=Arabic
allLocales.add(new Locale("en", "AS")); // American Samoa / lang=English
allLocales.add(new Locale("ca", "AD")); // Andorra / lang=Catalan
allLocales.add(new Locale("pt", "AO")); // Angola / lang=Portuguese
allLocales.add(new Locale("en", "AI")); // Anguilla / lang=English
allLocales.add(new Locale("en", "AG")); // Antigua and Barbuda / lang=English
allLocales.add(new Locale("es", "AR")); // Argentina / lang=Spanish
allLocales.add(new Locale("hy", "AM")); // Armenia / lang=Armenian
allLocales.add(new Locale("nl", "AW")); // Aruba / lang=Dutch
allLocales.add(new Locale("en", "AU")); // Australia / lang=English
allLocales.add(new Locale("de", "AT")); // Austria / lang=German
allLocales.add(new Locale("az", "AZ")); // Azerbaijan / lang=Azerbaijani
allLocales.add(new Locale("en", "BS")); // Bahamas / lang=English
allLocales.add(new Locale("ar", "BH")); // Bahrain / lang=Arabic
allLocales.add(new Locale("bn", "BD")); // Bangladesh / lang=Bengali
allLocales.add(new Locale("en", "BB")); // Barbados / lang=English
allLocales.add(new Locale("be", "BY")); // Belarus / lang=Belarusian
allLocales.add(new Locale("nl", "BE")); // Belgium / lang=Dutch
allLocales.add(new Locale("en", "BZ")); // Belize / lang=English
allLocales.add(new Locale("fr", "BJ")); // Benin / lang=French
allLocales.add(new Locale("en", "BM")); // Bermuda / lang=English
allLocales.add(new Locale("dz", "BT")); // Bhutan / lang=Dzongkha
allLocales.add(new Locale("es", "BO")); // Bolivia (Plurinational State of) / lang=Spanish
allLocales.add(new Locale("nl", "BQ")); // Bonaire, Sint Eustatius and Saba / lang=Dutch
allLocales.add(new Locale("bs", "BA")); // Bosnia and Herzegovina / lang=Bosnian
allLocales.add(new Locale("en", "BW")); // Botswana / lang=English
allLocales.add(new Locale("pt", "BR")); // Brazil / lang=Portuguese
allLocales.add(new Locale("en", "IO")); // British Indian Ocean Territory / lang=English
allLocales.add(new Locale("en", "UM")); // United States Minor Outlying Islands / lang=English
allLocales.add(new Locale("en", "VG")); // Virgin Islands (British) / lang=English
allLocales.add(new Locale("en", "VI")); // Virgin Islands (U.S.) / lang=English
allLocales.add(new Locale("ms", "BN")); // Brunei Darussalam / lang=Malay
allLocales.add(new Locale("bg", "BG")); // Bulgaria / lang=Bulgarian
allLocales.add(new Locale("fr", "BF")); // Burkina Faso / lang=French
allLocales.add(new Locale("fr", "BI")); // Burundi / lang=French
allLocales.add(new Locale("km", "KH")); // Cambodia / lang=Khmer
allLocales.add(new Locale("en", "CM")); // Cameroon / lang=English
allLocales.add(new Locale("en", "CA")); // Canada / lang=English
allLocales.add(new Locale("pt", "CV")); // Cabo Verde / lang=Portuguese
allLocales.add(new Locale("en", "KY")); // Cayman Islands / lang=English
allLocales.add(new Locale("fr", "CF")); // Central African Republic / lang=French
allLocales.add(new Locale("fr", "TD")); // Chad / lang=French
allLocales.add(new Locale("es", "CL")); // Chile / lang=Spanish
allLocales.add(new Locale("zh", "CN")); // China / lang=Chinese
allLocales.add(new Locale("en", "CX")); // Christmas Island / lang=English
allLocales.add(new Locale("en", "CC")); // Cocos (Keeling) Islands / lang=English
allLocales.add(new Locale("es", "CO")); // Colombia / lang=Spanish
allLocales.add(new Locale("ar", "KM")); // Comoros / lang=Arabic
allLocales.add(new Locale("fr", "CG")); // Congo / lang=French
allLocales.add(new Locale("fr", "CD")); // Congo (Democratic Republic of the) / lang=French
allLocales.add(new Locale("en", "CK")); // Cook Islands / lang=English
allLocales.add(new Locale("es", "CR")); // Costa Rica / lang=Spanish
allLocales.add(new Locale("hr", "HR")); // Croatia / lang=Croatian
allLocales.add(new Locale("es", "CU")); // Cuba / lang=Spanish
allLocales.add(new Locale("nl", "CW")); // Curaçao / lang=Dutch
allLocales.add(new Locale("el", "CY")); // Cyprus / lang=Greek (modern)
allLocales.add(new Locale("cs", "CZ")); // Czech Republic / lang=Czech
allLocales.add(new Locale("da", "DK")); // Denmark / lang=Danish
allLocales.add(new Locale("fr", "DJ")); // Djibouti / lang=French
allLocales.add(new Locale("en", "DM")); // Dominica / lang=English
allLocales.add(new Locale("es", "DO")); // Dominican Republic / lang=Spanish
allLocales.add(new Locale("es", "EC")); // Ecuador / lang=Spanish
allLocales.add(new Locale("ar", "EG")); // Egypt / lang=Arabic
allLocales.add(new Locale("es", "SV")); // El Salvador / lang=Spanish
allLocales.add(new Locale("es", "GQ")); // Equatorial Guinea / lang=Spanish
allLocales.add(new Locale("ti", "ER")); // Eritrea / lang=Tigrinya
allLocales.add(new Locale("et", "EE")); // Estonia / lang=Estonian
allLocales.add(new Locale("am", "ET")); // Ethiopia / lang=Amharic
allLocales.add(new Locale("en", "FK")); // Falkland Islands (Malvinas) / lang=English
allLocales.add(new Locale("fo", "FO")); // Faroe Islands / lang=Faroese
allLocales.add(new Locale("en", "FJ")); // Fiji / lang=English
allLocales.add(new Locale("fi", "FI")); // Finland / lang=Finnish
allLocales.add(new Locale("fr", "FR")); // France / lang=French
allLocales.add(new Locale("fr", "GF")); // French Guiana / lang=French
allLocales.add(new Locale("fr", "PF")); // French Polynesia / lang=French
allLocales.add(new Locale("fr", "TF")); // French Southern Territories / lang=French
allLocales.add(new Locale("fr", "GA")); // Gabon / lang=French
allLocales.add(new Locale("en", "GM")); // Gambia / lang=English
allLocales.add(new Locale("ka", "GE")); // Georgia / lang=Georgian
allLocales.add(new Locale("de", "DE")); // Germany / lang=German
allLocales.add(new Locale("en", "GH")); // Ghana / lang=English
allLocales.add(new Locale("en", "GI")); // Gibraltar / lang=English
allLocales.add(new Locale("el", "GR")); // Greece / lang=Greek (modern)
allLocales.add(new Locale("kl", "GL")); // Greenland / lang=Kalaallisut
allLocales.add(new Locale("en", "GD")); // Grenada / lang=English
allLocales.add(new Locale("fr", "GP")); // Guadeloupe / lang=French
allLocales.add(new Locale("en", "GU")); // Guam / lang=English
allLocales.add(new Locale("es", "GT")); // Guatemala / lang=Spanish
allLocales.add(new Locale("en", "GG")); // Guernsey / lang=English
allLocales.add(new Locale("fr", "GN")); // Guinea / lang=French
allLocales.add(new Locale("pt", "GW")); // Guinea-Bissau / lang=Portuguese
allLocales.add(new Locale("en", "GY")); // Guyana / lang=English
allLocales.add(new Locale("fr", "HT")); // Haiti / lang=French
allLocales.add(new Locale("la", "VA")); // Holy See / lang=Latin
allLocales.add(new Locale("es", "HN")); // Honduras / lang=Spanish
allLocales.add(new Locale("en", "HK")); // Hong Kong / lang=English
allLocales.add(new Locale("hu", "HU")); // Hungary / lang=Hungarian
allLocales.add(new Locale("is", "IS")); // Iceland / lang=Icelandic
allLocales.add(new Locale("hi", "IN")); // India / lang=Hindi
allLocales.add(new Locale("id", "ID")); // Indonesia / lang=Indonesian
allLocales.add(new Locale("fr", "CI")); // Côte d'Ivoire / lang=French
allLocales.add(new Locale("fa", "IR")); // Iran (Islamic Republic of) / lang=Persian (Farsi)
allLocales.add(new Locale("ar", "IQ")); // Iraq / lang=Arabic
allLocales.add(new Locale("ga", "IE")); // Ireland / lang=Irish
allLocales.add(new Locale("en", "IM")); // Isle of Man / lang=English
allLocales.add(new Locale("he", "IL")); // Israel / lang=Hebrew (modern)
allLocales.add(new Locale("it", "IT")); // Italy / lang=Italian
allLocales.add(new Locale("en", "JM")); // Jamaica / lang=English
allLocales.add(new Locale("ja", "JP")); // Japan / lang=Japanese
allLocales.add(new Locale("en", "JE")); // Jersey / lang=English
allLocales.add(new Locale("ar", "JO")); // Jordan / lang=Arabic
allLocales.add(new Locale("kk", "KZ")); // Kazakhstan / lang=Kazakh
allLocales.add(new Locale("en", "KE")); // Kenya / lang=English
allLocales.add(new Locale("en", "KI")); // Kiribati / lang=English
allLocales.add(new Locale("ar", "KW")); // Kuwait / lang=Arabic
allLocales.add(new Locale("ky", "KG")); // Kyrgyzstan / lang=Kyrgyz
allLocales.add(new Locale("lo", "LA")); // Lao People's Democratic Republic / lang=Lao
allLocales.add(new Locale("lv", "LV")); // Latvia / lang=Latvian
allLocales.add(new Locale("ar", "LB")); // Lebanon / lang=Arabic
allLocales.add(new Locale("en", "LS")); // Lesotho / lang=English
allLocales.add(new Locale("en", "LR")); // Liberia / lang=English
allLocales.add(new Locale("ar", "LY")); // Libya / lang=Arabic
allLocales.add(new Locale("de", "LI")); // Liechtenstein / lang=German
allLocales.add(new Locale("lt", "LT")); // Lithuania / lang=Lithuanian
allLocales.add(new Locale("fr", "LU")); // Luxembourg / lang=French
allLocales.add(new Locale("zh", "MO")); // Macao / lang=Chinese
allLocales.add(new Locale("mk", "MK")); // Macedonia (the former Yugoslav Republic of) / lang=Macedonian
allLocales.add(new Locale("fr", "MG")); // Madagascar / lang=French
allLocales.add(new Locale("en", "MW")); // Malawi / lang=English
allLocales.add(new Locale("en", "MY")); // Malaysia / lang=Malaysian
allLocales.add(new Locale("dv", "MV")); // Maldives / lang=Divehi
allLocales.add(new Locale("fr", "ML")); // Mali / lang=French
allLocales.add(new Locale("mt", "MT")); // Malta / lang=Maltese
allLocales.add(new Locale("en", "MH")); // Marshall Islands / lang=English
allLocales.add(new Locale("fr", "MQ")); // Martinique / lang=French
allLocales.add(new Locale("ar", "MR")); // Mauritania / lang=Arabic
allLocales.add(new Locale("en", "MU")); // Mauritius / lang=English
allLocales.add(new Locale("fr", "YT")); // Mayotte / lang=French
allLocales.add(new Locale("es", "MX")); // Mexico / lang=Spanish
allLocales.add(new Locale("en", "FM")); // Micronesia (Federated States of) / lang=English
allLocales.add(new Locale("ro", "MD")); // Moldova (Republic of) / lang=Romanian
allLocales.add(new Locale("fr", "MC")); // Monaco / lang=French
allLocales.add(new Locale("mn", "MN")); // Mongolia / lang=Mongolian
allLocales.add(new Locale("sr", "ME")); // Montenegro / lang=Serbian
allLocales.add(new Locale("en", "MS")); // Montserrat / lang=English
allLocales.add(new Locale("ar", "MA")); // Morocco / lang=Arabic
allLocales.add(new Locale("pt", "MZ")); // Mozambique / lang=Portuguese
allLocales.add(new Locale("my", "MM")); // Myanmar / lang=Burmese
allLocales.add(new Locale("en", "NA")); // Namibia / lang=English
allLocales.add(new Locale("en", "NR")); // Nauru / lang=English
allLocales.add(new Locale("ne", "NP")); // Nepal / lang=Nepali
allLocales.add(new Locale("nl", "NL")); // Netherlands / lang=Dutch
allLocales.add(new Locale("fr", "NC")); // New Caledonia / lang=French
allLocales.add(new Locale("en", "NZ")); // New Zealand / lang=English
allLocales.add(new Locale("es", "NI")); // Nicaragua / lang=Spanish
allLocales.add(new Locale("fr", "NE")); // Niger / lang=French
allLocales.add(new Locale("en", "NG")); // Nigeria / lang=English
allLocales.add(new Locale("en", "NU")); // Niue / lang=English
allLocales.add(new Locale("en", "NF")); // Norfolk Island / lang=English
allLocales.add(new Locale("ko", "KP")); // Korea (Democratic People's Republic of) / lang=Korean
allLocales.add(new Locale("en", "MP")); // Northern Mariana Islands / lang=English
allLocales.add(new Locale("no", "NO")); // Norway / lang=Norwegian
allLocales.add(new Locale("ar", "OM")); // Oman / lang=Arabic
allLocales.add(new Locale("en", "PK")); // Pakistan / lang=English
allLocales.add(new Locale("en", "PW")); // Palau / lang=English
allLocales.add(new Locale("ar", "PS")); // Palestine, State of / lang=Arabic
allLocales.add(new Locale("es", "PA")); // Panama / lang=Spanish
allLocales.add(new Locale("en", "PG")); // Papua New Guinea / lang=English
allLocales.add(new Locale("es", "PY")); // Paraguay / lang=Spanish
allLocales.add(new Locale("es", "PE")); // Peru / lang=Spanish
allLocales.add(new Locale("en", "PH")); // Philippines / lang=English
allLocales.add(new Locale("en", "PN")); // Pitcairn / lang=English
allLocales.add(new Locale("pl", "PL")); // Poland / lang=Polish
allLocales.add(new Locale("pt", "PT")); // Portugal / lang=Portuguese
allLocales.add(new Locale("es", "PR")); // Puerto Rico / lang=Spanish
allLocales.add(new Locale("ar", "QA")); // Qatar / lang=Arabic
allLocales.add(new Locale("sq", "XK")); // Republic of Kosovo / lang=Albanian
allLocales.add(new Locale("fr", "RE")); // Réunion / lang=French
allLocales.add(new Locale("ro", "RO")); // Romania / lang=Romanian
allLocales.add(new Locale("ru", "RU")); // Russian Federation / lang=Russian
allLocales.add(new Locale("rw", "RW")); // Rwanda / lang=Kinyarwanda
allLocales.add(new Locale("fr", "BL")); // Saint Barthélemy / lang=French
allLocales.add(new Locale("en", "SH")); // Saint Helena, Ascension and Tristan da Cunha / lang=English
allLocales.add(new Locale("en", "KN")); // Saint Kitts and Nevis / lang=English
allLocales.add(new Locale("en", "LC")); // Saint Lucia / lang=English
allLocales.add(new Locale("en", "MF")); // Saint Martin (French part) / lang=English
allLocales.add(new Locale("fr", "PM")); // Saint Pierre and Miquelon / lang=French
allLocales.add(new Locale("en", "VC")); // Saint Vincent and the Grenadines / lang=English
allLocales.add(new Locale("sm", "WS")); // Samoa / lang=Samoan
allLocales.add(new Locale("it", "SM")); // San Marino / lang=Italian
allLocales.add(new Locale("pt", "ST")); // Sao Tome and Principe / lang=Portuguese
allLocales.add(new Locale("ar", "SA")); // Saudi Arabia / lang=Arabic
allLocales.add(new Locale("fr", "SN")); // Senegal / lang=French
allLocales.add(new Locale("sr", "RS")); // Serbia / lang=Serbian
allLocales.add(new Locale("fr", "SC")); // Seychelles / lang=French
allLocales.add(new Locale("en", "SL")); // Sierra Leone / lang=English
allLocales.add(new Locale("en", "SG")); // Singapore / lang=English
allLocales.add(new Locale("nl", "SX")); // Sint Maarten (Dutch part) / lang=Dutch
allLocales.add(new Locale("sk", "SK")); // Slovakia / lang=Slovak
allLocales.add(new Locale("sl", "SI")); // Slovenia / lang=Slovene
allLocales.add(new Locale("en", "SB")); // Solomon Islands / lang=English
allLocales.add(new Locale("so", "SO")); // Somalia / lang=Somali
allLocales.add(new Locale("af", "ZA")); // South Africa / lang=Afrikaans
allLocales.add(new Locale("en", "GS")); // South Georgia and the South Sandwich Islands / lang=English
allLocales.add(new Locale("ko", "KR")); // Korea (Republic of) / lang=Korean
allLocales.add(new Locale("en", "SS")); // South Sudan / lang=English
allLocales.add(new Locale("es", "ES")); // Spain / lang=Spanish
allLocales.add(new Locale("si", "LK")); // Sri Lanka / lang=Sinhalese
allLocales.add(new Locale("ar", "SD")); // Sudan / lang=Arabic
allLocales.add(new Locale("nl", "SR")); // Suriname / lang=Dutch
allLocales.add(new Locale("no", "SJ")); // Svalbard and Jan Mayen / lang=Norwegian
allLocales.add(new Locale("en", "SZ")); // Swaziland / lang=English
allLocales.add(new Locale("sv", "SE")); // Sweden / lang=Swedish
allLocales.add(new Locale("de", "CH")); // Switzerland / lang=German
allLocales.add(new Locale("ar", "SY")); // Syrian Arab Republic / lang=Arabic
allLocales.add(new Locale("zh", "TW")); // Taiwan / lang=Chinese
allLocales.add(new Locale("tg", "TJ")); // Tajikistan / lang=Tajik
allLocales.add(new Locale("sw", "TZ")); // Tanzania, United Republic of / lang=Swahili
allLocales.add(new Locale("th", "TH")); // Thailand / lang=Thai
allLocales.add(new Locale("pt", "TL")); // Timor-Leste / lang=Portuguese
allLocales.add(new Locale("fr", "TG")); // Togo / lang=French
allLocales.add(new Locale("en", "TK")); // Tokelau / lang=English
allLocales.add(new Locale("en", "TO")); // Tonga / lang=English
allLocales.add(new Locale("en", "TT")); // Trinidad and Tobago / lang=English
allLocales.add(new Locale("ar", "TN")); // Tunisia / lang=Arabic
allLocales.add(new Locale("tr", "TR")); // Turkey / lang=Turkish
allLocales.add(new Locale("tk", "TM")); // Turkmenistan / lang=Turkmen
allLocales.add(new Locale("en", "TC")); // Turks and Caicos Islands / lang=English
allLocales.add(new Locale("en", "TV")); // Tuvalu / lang=English
allLocales.add(new Locale("en", "UG")); // Uganda / lang=English
allLocales.add(new Locale("uk", "UA")); // Ukraine / lang=Ukrainian
allLocales.add(new Locale("ar", "AE")); // United Arab Emirates / lang=Arabic
allLocales.add(new Locale("en", "GB")); // United Kingdom of Great Britain and Northern Ireland / lang=English
allLocales.add(new Locale("en", "US")); // United States of America / lang=English
allLocales.add(new Locale("es", "UY")); // Uruguay / lang=Spanish
allLocales.add(new Locale("uz", "UZ")); // Uzbekistan / lang=Uzbek
allLocales.add(new Locale("bi", "VU")); // Vanuatu / lang=Bislama
allLocales.add(new Locale("es", "VE")); // Venezuela (Bolivarian Republic of) / lang=Spanish
allLocales.add(new Locale("vi", "VN")); // Viet Nam / lang=Vietnamese
allLocales.add(new Locale("fr", "WF")); // Wallis and Futuna / lang=French
allLocales.add(new Locale("es", "EH")); // Western Sahara / lang=Spanish
allLocales.add(new Locale("ar", "YE")); // Yemen / lang=Arabic
allLocales.add(new Locale("en", "ZM")); // Zambia / lang=English
allLocales.add(new Locale("en", "ZW")); // Zimbabwe / lang=English
return allLocales;
}
}

View File

@ -1,48 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import com.google.protobuf.Message;
import io.bisq.common.proto.persistable.PersistablePayload;
import io.bisq.generated.protobuffer.PB;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.annotation.concurrent.Immutable;
@Immutable
@EqualsAndHashCode
@ToString
public final class Region implements PersistablePayload {
public final String code;
public final String name;
public Region(String code, String name) {
this.code = code;
this.name = name;
}
@Override
public Message toProtoMessage() {
return PB.Region.newBuilder().setCode(code).setName(name).build();
}
public static Region fromProto(PB.Region proto) {
return new Region(proto.getCode(), proto.getName());
}
}

View File

@ -1,146 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import io.bisq.common.GlobalSettings;
import io.bisq.common.app.DevEnv;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
public class Res {
private static final Logger log = LoggerFactory.getLogger(Res.class);
@SuppressWarnings("CanBeFinal")
private static ResourceBundle resourceBundle = ResourceBundle.getBundle("i18n.displayStrings", GlobalSettings.getLocale(), new UTF8Control());
static {
GlobalSettings.localeProperty().addListener((observable, oldValue, newValue) -> {
if ("en".equalsIgnoreCase(newValue.getLanguage()))
newValue = Locale.ROOT;
resourceBundle = ResourceBundle.getBundle("i18n.displayStrings", newValue, new UTF8Control());
});
}
public static String getWithCol(String key) {
return get(key) + ":";
}
public static String getWithColAndCap(String key) {
return StringUtils.capitalize(get(key)) + ":";
}
public static ResourceBundle getResourceBundle() {
return resourceBundle;
}
private static String baseCurrencyCode;
private static String baseCurrencyName;
private static String baseCurrencyNameLowerCase;
public static void setBaseCurrencyCode(String baseCurrencyCode) {
Res.baseCurrencyCode = baseCurrencyCode;
}
public static void setBaseCurrencyName(String baseCurrencyName) {
Res.baseCurrencyName = baseCurrencyName;
baseCurrencyNameLowerCase = baseCurrencyName.toLowerCase();
}
public static String getBaseCurrencyCode() {
return baseCurrencyCode;
}
public static String getBaseCurrencyName() {
return baseCurrencyName;
}
// Capitalize first character
public static String getWithCap(String key) {
return StringUtils.capitalize(get(key));
}
public static String getWithCol(String key, Object... arguments) {
return get(key, arguments) + ":";
}
public static String get(String key, Object... arguments) {
return MessageFormat.format(Res.get(key), arguments);
}
public static String get(String key) {
try {
return resourceBundle.getString(key)
.replace("BTC", baseCurrencyCode)
.replace("Bitcoin", baseCurrencyName)
.replace("bitcoin", baseCurrencyNameLowerCase);
} catch (MissingResourceException e) {
log.warn("Missing resource for key: " + key);
if (DevEnv.isDevMode())
throw new RuntimeException("Missing resource for key: " + key);
return key;
}
}
}
// Adds UTF8 support for property files
class UTF8Control extends ResourceBundle.Control {
public ResourceBundle newBundle(String baseName, @NotNull Locale locale, @NotNull String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
// The below is a copy of the default implementation.
final String bundleName = toBundleName(baseName, locale);
final String resourceName = toResourceName(bundleName, "properties");
ResourceBundle bundle = null;
InputStream stream = null;
if (reload) {
final URL url = loader.getResource(resourceName);
if (url != null) {
final URLConnection connection = url.openConnection();
if (connection != null) {
connection.setUseCaches(false);
stream = connection.getInputStream();
}
}
} else {
stream = loader.getResourceAsStream(resourceName);
}
if (stream != null) {
try {
// Only this line is changed to make it to read properties files as UTF-8.
bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
} finally {
stream.close();
}
}
return bundle;
}
}

View File

@ -1,85 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.locale;
import io.bisq.common.proto.ProtobufferException;
import io.bisq.common.proto.persistable.PersistablePayload;
import io.bisq.generated.protobuffer.PB;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
@EqualsAndHashCode
@ToString
@Getter
@Slf4j
public abstract class TradeCurrency implements PersistablePayload, Comparable<TradeCurrency> {
protected final String code;
protected final String name;
public TradeCurrency(String code, String name) {
this.code = code;
this.name = name;
}
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
public static TradeCurrency fromProto(PB.TradeCurrency proto) {
switch (proto.getMessageCase()) {
case FIAT_CURRENCY:
return FiatCurrency.fromProto(proto);
case CRYPTO_CURRENCY:
return CryptoCurrency.fromProto(proto);
default:
throw new ProtobufferException("Unknown message case: " + proto.getMessageCase());
}
}
public PB.TradeCurrency.Builder getTradeCurrencyBuilder() {
return PB.TradeCurrency.newBuilder()
.setCode(code)
.setName(name);
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public String getDisplayPrefix() {
return "";
}
public String getNameAndCode() {
return name + " (" + code + ")";
}
public String getCodeAndName() {
return code + " (" + name + ")";
}
@Override
public int compareTo(@NotNull TradeCurrency other) {
return this.name.compareTo(other.name);
}
}

View File

@ -1,198 +0,0 @@
package io.bisq.common.monetary;
import com.google.common.math.LongMath;
import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.MonetaryFormat;
import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Cloned from Fiat class and altered SMALLEST_UNIT_EXPONENT as Fiat is final.
* <p/>
* Represents a monetary fiat value. It was decided to not fold this into {@link org.bitcoinj.core.Coin} because of type
* safety. Volume values always come with an attached currency code.
* <p/>
* This class is immutable.
*/
public final class Altcoin implements Monetary, Comparable<Altcoin> {
/**
* The absolute value of exponent of the value of a "smallest unit" in scientific notation. We picked 4 rather than
* 2, because in financial applications it's common to use sub-cent precision.
*/
public static final int SMALLEST_UNIT_EXPONENT = 8;
private static final MonetaryFormat FRIENDLY_FORMAT = new MonetaryFormat().shift(0).minDecimals(2).repeatOptionalDecimals(2, 1).postfixCode();
private static final MonetaryFormat PLAIN_FORMAT = new MonetaryFormat().shift(0).minDecimals(0).repeatOptionalDecimals(1, 8).noCode();
/**
* The number of smallest units of this monetary value.
*/
public final long value;
public final String currencyCode;
private Altcoin(final String currencyCode, final long value) {
this.value = value;
this.currencyCode = currencyCode;
}
public static Altcoin valueOf(final String currencyCode, final long value) {
return new Altcoin(currencyCode, value);
}
@Override
public int smallestUnitExponent() {
return SMALLEST_UNIT_EXPONENT;
}
/**
* Returns the number of "smallest units" of this monetary value.
*/
@Override
public long getValue() {
return value;
}
public String getCurrencyCode() {
return currencyCode;
}
/**
* Parses an amount expressed in the way humans are used to.
* <p/>
* <p/>
* This takes string in a format understood by {@link BigDecimal#BigDecimal(String)}, for example "0", "1", "0.10",
* "1.23E3", "1234.5E-5".
*
* @throws IllegalArgumentException if you try to specify fractional satoshis, or a value out of range.
*/
public static Altcoin parseAltcoin(final String currencyCode, String inputValue) {
inputValue = inputValue.replace(",", ".");
try {
long val = new BigDecimal(inputValue).movePointRight(SMALLEST_UNIT_EXPONENT)
.toBigIntegerExact().longValue();
return Altcoin.valueOf(currencyCode, val);
} catch (ArithmeticException e) {
throw new IllegalArgumentException(e);
}
}
public Altcoin add(final Altcoin value) {
checkArgument(value.currencyCode.equals(currencyCode));
return new Altcoin(currencyCode, LongMath.checkedAdd(this.value, value.value));
}
public Altcoin subtract(final Altcoin value) {
checkArgument(value.currencyCode.equals(currencyCode));
return new Altcoin(currencyCode, LongMath.checkedSubtract(this.value, value.value));
}
public Altcoin multiply(final long factor) {
return new Altcoin(currencyCode, LongMath.checkedMultiply(this.value, factor));
}
public Altcoin divide(final long divisor) {
return new Altcoin(currencyCode, this.value / divisor);
}
public Altcoin[] divideAndRemainder(final long divisor) {
return new Altcoin[]{new Altcoin(currencyCode, this.value / divisor), new Altcoin(currencyCode, this.value % divisor)};
}
public long divide(final Altcoin divisor) {
checkArgument(divisor.currencyCode.equals(currencyCode));
return this.value / divisor.value;
}
/**
* Returns true if and only if this instance represents a monetary value greater than zero, otherwise false.
*/
public boolean isPositive() {
return signum() == 1;
}
/**
* Returns true if and only if this instance represents a monetary value less than zero, otherwise false.
*/
public boolean isNegative() {
return signum() == -1;
}
/**
* Returns true if and only if this instance represents zero monetary value, otherwise false.
*/
public boolean isZero() {
return signum() == 0;
}
/**
* Returns true if the monetary value represented by this instance is greater than that of the given other Coin,
* otherwise false.
*/
public boolean isGreaterThan(Altcoin other) {
return compareTo(other) > 0;
}
/**
* Returns true if the monetary value represented by this instance is less than that of the given other Coin,
* otherwise false.
*/
public boolean isLessThan(Altcoin other) {
return compareTo(other) < 0;
}
@Override
public int signum() {
if (this.value == 0)
return 0;
return this.value < 0 ? -1 : 1;
}
public Altcoin negate() {
return new Altcoin(currencyCode, -this.value);
}
public String toFriendlyString() {
return FRIENDLY_FORMAT.code(0, currencyCode).format(this).toString();
}
/**
* <p>
* Returns the value as a plain string denominated in BTC. The result is unformatted with no trailing zeroes. For
* instance, a value of 150000 satoshis gives an output string of "0.0015" BTC
* </p>
*/
public String toPlainString() {
return PLAIN_FORMAT.format(this).toString();
}
@Override
public String toString() {
return toPlainString();
}
@Override
public boolean equals(final Object o) {
if (o == this)
return true;
if (o == null || o.getClass() != getClass())
return false;
final Altcoin other = (Altcoin) o;
return this.value == other.value && this.currencyCode.equals(other.currencyCode);
}
@Override
public int hashCode() {
return (int) this.value + 37 * this.currencyCode.hashCode();
}
@Override
public int compareTo(@NotNull final Altcoin other) {
if (!this.currencyCode.equals(other.currencyCode))
return this.currencyCode.compareTo(other.currencyCode);
if (this.value != other.value)
return this.value > other.value ? 1 : -1;
return 0;
}
}

View File

@ -1,75 +0,0 @@
package io.bisq.common.monetary;
import lombok.extern.slf4j.Slf4j;
import org.bitcoinj.core.Coin;
import java.math.BigInteger;
import static com.google.common.base.Preconditions.checkArgument;
// Cloned from ExchangeRate. Use Altcoin instead of Fiat.
@Slf4j
public class AltcoinExchangeRate {
/**
* An exchange rate is expressed as a ratio of a {@link Coin} and a {@link Altcoin} amount.
*/
public final Coin coin;
public final Altcoin altcoin;
/**
* Construct exchange rate. This amount of coin is worth that amount of altcoin.
*/
@SuppressWarnings("SameParameterValue")
public AltcoinExchangeRate(Coin coin, Altcoin altcoin) {
checkArgument(coin.isPositive());
checkArgument(altcoin.isPositive());
checkArgument(altcoin.currencyCode != null, "currency code required");
this.coin = coin;
this.altcoin = altcoin;
}
/**
* Construct exchange rate. One coin is worth this amount of altcoin.
*/
public AltcoinExchangeRate(Altcoin altcoin) {
this(Coin.COIN, altcoin);
}
/**
* Convert a coin amount to a altcoin amount using this exchange rate.
*
* @throws ArithmeticException if the converted altcoin amount is too high or too low.
*/
public Altcoin coinToAltcoin(Coin convertCoin) {
BigInteger converted = BigInteger.valueOf(coin.value)
.multiply(BigInteger.valueOf(convertCoin.value))
.divide(BigInteger.valueOf(altcoin.value));
if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0
|| converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0)
throw new ArithmeticException("Overflow");
return Altcoin.valueOf(altcoin.currencyCode, converted.longValue());
}
/**
* Convert a altcoin amount to a coin amount using this exchange rate.
*
* @throws ArithmeticException if the converted coin amount is too high or too low.
*/
public Coin altcoinToCoin(Altcoin convertAltcoin) {
checkArgument(convertAltcoin.currencyCode.equals(altcoin.currencyCode), "Currency mismatch: %s vs %s",
convertAltcoin.currencyCode, altcoin.currencyCode);
// Use BigInteger because it's much easier to maintain full precision without overflowing.
BigInteger converted = BigInteger.valueOf(altcoin.value)
.multiply(BigInteger.valueOf(convertAltcoin.value))
.divide(BigInteger.valueOf(coin.value));
if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0
|| converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0)
throw new ArithmeticException("Overflow");
try {
return Coin.valueOf(converted.longValue());
} catch (IllegalArgumentException x) {
throw new ArithmeticException("Overflow: " + x.getMessage());
}
}
}

View File

@ -1,50 +0,0 @@
package io.bisq.common.monetary;
import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.MonetaryFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class MonetaryWrapper {
private static final Logger log = LoggerFactory.getLogger(MonetaryWrapper.class);
/// Instance of Fiat or Altcoin
protected final Monetary monetary;
protected final MonetaryFormat fiatFormat = MonetaryFormat.FIAT.repeatOptionalDecimals(0, 0);
protected final MonetaryFormat altCoinFormat = MonetaryFormat.FIAT.repeatOptionalDecimals(0, 0);
public MonetaryWrapper(Monetary monetary) {
this.monetary = monetary;
}
public Monetary getMonetary() {
return monetary;
}
public boolean isZero() {
return monetary.getValue() == 0;
}
public int smallestUnitExponent() {
return monetary.smallestUnitExponent();
}
public long getValue() {
return monetary.getValue();
}
@Override
public boolean equals(final Object o) {
if (o == this)
return true;
if (o == null || o.getClass() != getClass())
return false;
final Monetary otherMonetary = ((MonetaryWrapper) o).getMonetary();
return monetary.getValue() == otherMonetary.getValue();
}
@Override
public int hashCode() {
return (int) monetary.getValue();
}
}

View File

@ -1,103 +0,0 @@
package io.bisq.common.monetary;
import io.bisq.common.locale.CurrencyUtil;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.ExchangeRate;
import org.bitcoinj.utils.Fiat;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Wrapper for price values with variable precision. If monetary is Altcoin we use precision 8 otherwise Fiat with precision 4.
* The inverted price notation in the offer will be refactored once in a bigger refactoring update.
*/
public class Price extends MonetaryWrapper implements Comparable<Price> {
private static final Logger log = LoggerFactory.getLogger(Price.class);
public Price(Monetary monetary) {
super(monetary);
}
public static Price parse(String currencyCode, String inputValue) {
final String cleaned = inputValue.replace(",", ".");
if (CurrencyUtil.isFiatCurrency(currencyCode))
return new Price(Fiat.parseFiat(currencyCode, cleaned));
else
return new Price(Altcoin.parseAltcoin(currencyCode, cleaned));
}
public static Price valueOf(String currencyCode, long value) {
if (CurrencyUtil.isFiatCurrency(currencyCode)) {
return new Price(Fiat.valueOf(currencyCode, value));
} else {
return new Price(Altcoin.valueOf(currencyCode, value));
}
}
public Volume getVolumeByAmount(Coin amount) {
if (monetary instanceof Fiat)
return new Volume(new ExchangeRate((Fiat) monetary).coinToFiat(amount));
else if (monetary instanceof Altcoin)
return new Volume(new AltcoinExchangeRate((Altcoin) monetary).coinToAltcoin(amount));
else
throw new IllegalStateException("Monetary must be either of type Fiat or Altcoin");
}
public Coin getAmountByVolume(Volume volume) {
Monetary monetary = volume.getMonetary();
if (monetary instanceof Fiat && this.monetary instanceof Fiat)
return new ExchangeRate((Fiat) this.monetary).fiatToCoin((Fiat) monetary);
else if (monetary instanceof Altcoin && this.monetary instanceof Altcoin)
return new AltcoinExchangeRate((Altcoin) this.monetary).altcoinToCoin((Altcoin) monetary);
else
return Coin.ZERO;
}
private static int getPrecision(String currencyCode) {
return CurrencyUtil.isCryptoCurrency(currencyCode) ? 8 : 4;
}
public String getCurrencyCode() {
return monetary instanceof Altcoin ? ((Altcoin) monetary).getCurrencyCode() : ((Fiat) monetary).getCurrencyCode();
}
public long getValue() {
return monetary.getValue();
}
@Override
public int compareTo(@NotNull Price other) {
if (!this.getCurrencyCode().equals(other.getCurrencyCode()))
return this.getCurrencyCode().compareTo(other.getCurrencyCode());
if (this.getValue() != other.getValue())
return this.getValue() > other.getValue() ? 1 : -1;
return 0;
}
public boolean isPositive() {
return monetary instanceof Altcoin ? ((Altcoin) monetary).isPositive() : ((Fiat) monetary).isPositive();
}
public Price subtract(Price other) {
if (monetary instanceof Altcoin) {
return new Price(((Altcoin) monetary).subtract((Altcoin) other.monetary));
} else {
return new Price(((Fiat) monetary).subtract((Fiat) other.monetary));
}
}
public String toFriendlyString() {
return monetary instanceof Altcoin ? ((Altcoin) monetary).toFriendlyString() : ((Fiat) monetary).toFriendlyString();
}
public String toPlainString() {
return monetary instanceof Altcoin ? ((Altcoin) monetary).toPlainString() : ((Fiat) monetary).toPlainString();
}
@Override
public String toString() {
return toPlainString();
}
}

View File

@ -1,46 +0,0 @@
package io.bisq.common.monetary;
import io.bisq.common.locale.CurrencyUtil;
import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.Fiat;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Volume extends MonetaryWrapper implements Comparable<Volume> {
private static final Logger log = LoggerFactory.getLogger(Volume.class);
public Volume(Monetary monetary) {
super(monetary);
}
public static Volume parse(String inputValue, String currencyCode) {
final String cleaned = inputValue.replace(",", ".");
if (CurrencyUtil.isFiatCurrency(currencyCode))
return new Volume(Fiat.parseFiat(currencyCode, cleaned));
else
return new Volume(Altcoin.parseAltcoin(currencyCode, cleaned));
}
@Override
public int compareTo(@NotNull Volume other) {
if (!this.getCurrencyCode().equals(other.getCurrencyCode()))
return this.getCurrencyCode().compareTo(other.getCurrencyCode());
if (this.getValue() != other.getValue())
return this.getValue() > other.getValue() ? 1 : -1;
return 0;
}
public String getCurrencyCode() {
return monetary instanceof Altcoin ? ((Altcoin) monetary).getCurrencyCode() : ((Fiat) monetary).getCurrencyCode();
}
public String toPlainString() {
return monetary instanceof Altcoin ? ((Altcoin) monetary).toPlainString() : ((Fiat) monetary).toPlainString();
}
@Override
public String toString() {
return toPlainString();
}
}

View File

@ -1,28 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto;
import io.bisq.common.Payload;
import io.bisq.common.proto.persistable.PersistableEnvelope;
import io.bisq.generated.protobuffer.PB;
public interface ProtoResolver {
Payload fromProto(PB.PaymentAccountPayload proto);
PersistableEnvelope fromProto(PB.PersistableNetworkPayload proto);
}

View File

@ -1,90 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto;
import com.google.common.base.Enums;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import io.bisq.common.Proto;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
public class ProtoUtil {
public static Set<byte[]> byteSetFromProtoByteStringList(List<ByteString> byteStringList) {
return byteStringList.stream().map(ByteString::toByteArray).collect(Collectors.toSet());
}
/**
* Returns the input String, except when it's the empty string: "", then null is returned.
* Note: "" is the default value for a protobuffer string, so this means it's not filled in.
*/
@Nullable
public static String stringOrNullFromProto(String proto) {
return "".equals(proto) ? null : proto;
}
@Nullable
public static byte[] byteArrayOrNullFromProto(ByteString proto) {
return proto.isEmpty() ? null : proto.toByteArray();
}
/**
* Get a Java enum from a Protobuf enum in a safe way.
*
* @param enumType the class of the enum, e.g: BlaEnum.class
* @param name the name of the enum entry, e.g: proto.getWinner().name()
* @param <E> the enum Type
* @return an enum
*/
public static <E extends Enum<E>> E enumFromProto(Class<E> enumType, String name) {
E result = Enums.getIfPresent(enumType, name).orNull();
if (result == null) {
log.error("Invalid value for enum " + enumType.getSimpleName() + ": " + name);
}
return result;
}
public static <T extends Message> Iterable<T> collectionToProto(Collection<? extends Proto> collection) {
return collection.stream()
.map(e -> {
final Message message = e.toProtoMessage();
try {
//noinspection unchecked
return (T) message;
} catch (Throwable t) {
log.error("message could not be casted. message=" + message);
return null;
}
})
.filter(e -> e != null)
.collect(Collectors.toList());
}
public static <T> Iterable<T> collectionToProto(Collection<? extends Proto> collection, Function<? super Message, T> extra) {
return collection.stream().map(o -> extra.apply(o.toProtoMessage())).collect(Collectors.toList());
}
}

View File

@ -1,28 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto;
public class ProtobufferException extends RuntimeException {
public ProtobufferException(String message) {
super(message);
}
public ProtobufferException(String message, Throwable e) {
super(message, e);
}
}

View File

@ -1,67 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto.network;
import com.google.protobuf.Message;
import io.bisq.common.Envelope;
import io.bisq.generated.protobuffer.PB;
import lombok.EqualsAndHashCode;
import static com.google.common.base.Preconditions.checkArgument;
@EqualsAndHashCode
public abstract class NetworkEnvelope implements Envelope {
protected final int messageVersion;
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
protected NetworkEnvelope(int messageVersion) {
this.messageVersion = messageVersion;
}
public PB.NetworkEnvelope.Builder getNetworkEnvelopeBuilder() {
return PB.NetworkEnvelope.newBuilder().setMessageVersion(messageVersion);
}
@Override
public Message toProtoMessage() {
return getNetworkEnvelopeBuilder().build();
}
// todo remove
public PB.NetworkEnvelope toProtoNetworkEnvelope() {
return getNetworkEnvelopeBuilder().build();
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public int getMessageVersion() {
// -1 is used for the case that we use an envelope message as payload (mailbox)
// so we check only against 0 which is the default value if not set
checkArgument(messageVersion != 0, "messageVersion is not set (0).");
return messageVersion;
}
}

View File

@ -1,9 +0,0 @@
package io.bisq.common.proto.network;
import io.bisq.common.Payload;
/**
* Interface for objects used inside WireEnvelope or other WirePayloads.
*/
public interface NetworkPayload extends Payload {
}

View File

@ -1,29 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto.network;
import io.bisq.common.proto.ProtoResolver;
import io.bisq.generated.protobuffer.PB;
public interface NetworkProtoResolver extends ProtoResolver {
NetworkEnvelope fromProto(PB.NetworkEnvelope proto);
NetworkPayload fromProto(PB.StoragePayload proto);
NetworkPayload fromProto(PB.StorageEntryWrapper proto);
}

View File

@ -1,46 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto.persistable;
import com.google.protobuf.Message;
import io.bisq.generated.protobuffer.PB;
import lombok.*;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class NavigationPath implements PersistableEnvelope {
private List<String> path = new ArrayList<>();
@Override
public Message toProtoMessage() {
final PB.NavigationPath.Builder builder = PB.NavigationPath.newBuilder();
if (!CollectionUtils.isEmpty(path)) builder.addAllPath(path);
return PB.PersistableEnvelope.newBuilder().setNavigationPath(builder).build();
}
public static PersistableEnvelope fromProto(PB.NavigationPath proto) {
return new NavigationPath(new ArrayList<>(proto.getPathList()));
}
}

View File

@ -1,9 +0,0 @@
package io.bisq.common.proto.persistable;
import io.bisq.common.Envelope;
/**
* Interface for the outside envelope object persisted to disc.
*/
public interface PersistableEnvelope extends Envelope {
}

View File

@ -1,49 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto.persistable;
import com.google.protobuf.Message;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Delegate;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class PersistableHashMap<K, V extends PersistablePayload> implements PersistableEnvelope {
@Delegate
@Getter
private Map<K, V> map = new HashMap<>();
@Setter
private Function<Map<K, V>, Message> toProto;
public PersistableHashMap(Map<K, V> map) {
this.map = map;
}
public PersistableHashMap(Map<K, V> map, Function<Map<K, V>, Message> toProto) {
this(map);
this.toProto = toProto;
}
@Override
public Message toProtoMessage() {
return toProto.apply(map);
}
}

View File

@ -1,65 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto.persistable;
import com.google.protobuf.Message;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Delegate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class PersistableList<T extends PersistablePayload> implements PersistableEnvelope {
@Delegate
@Getter
@Setter
private List<T> list;
@Setter
private Function<List<T>, Message> toProto;
public PersistableList() {
list = new ArrayList<>();
}
public PersistableList(List<T> list) {
this.list = list;
}
public PersistableList(List<T> list, Function<List<T>, Message> toProto) {
this(list);
this.toProto = toProto;
}
public PersistableList(HashSet<T> set) {
this(set.stream().collect(Collectors.toList()));
}
public PersistableList(HashSet<T> set, Function<List<T>, Message> toProto) {
this(set);
this.toProto = toProto;
}
@Override
public Message toProtoMessage() {
return toProto.apply(list);
}
}

View File

@ -1,26 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto.persistable;
import io.bisq.common.Payload;
/**
* Interface for objects used inside Envelope or other Payloads.
*/
public interface PersistablePayload extends Payload {
}

View File

@ -1,22 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto.persistable;
public interface PersistedDataHost {
void readPersisted();
}

View File

@ -1,25 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.proto.persistable;
import io.bisq.common.proto.ProtoResolver;
import io.bisq.generated.protobuffer.PB;
public interface PersistenceProtoResolver extends ProtoResolver {
PersistableEnvelope fromProto(PB.PersistableEnvelope persistable);
}

View File

@ -1,244 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.storage;
import com.google.common.util.concurrent.CycleDetectingLockFactory;
import io.bisq.common.UserThread;
import io.bisq.common.proto.persistable.PersistableEnvelope;
import io.bisq.common.proto.persistable.PersistenceProtoResolver;
import io.bisq.common.util.Utilities;
import io.bisq.generated.protobuffer.PB;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.nio.file.Paths;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j
public class FileManager<T extends PersistableEnvelope> {
private final File dir;
private final File storageFile;
private final ScheduledThreadPoolExecutor executor;
private final AtomicBoolean savePending;
private final long delay;
private final Callable<Void> saveFileTask;
private T persistable;
private final PersistenceProtoResolver persistenceProtoResolver;
private final ReentrantLock writeLock = CycleDetectingLockFactory.newInstance(CycleDetectingLockFactory.Policies.THROW).newReentrantLock("writeLock");
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public FileManager(File dir, File storageFile, long delay, PersistenceProtoResolver persistenceProtoResolver) {
this.dir = dir;
this.storageFile = storageFile;
this.persistenceProtoResolver = persistenceProtoResolver;
executor = Utilities.getScheduledThreadPoolExecutor("FileManager", 1, 10, 5);
// File must only be accessed from the auto-save executor from now on, to avoid simultaneous access.
savePending = new AtomicBoolean();
this.delay = delay;
saveFileTask = () -> {
try {
Thread.currentThread().setName("Save-file-task-" + new Random().nextInt(10000));
// Runs in an auto save thread.
if (!savePending.getAndSet(false)) {
// Some other scheduled request already beat us to it.
return null;
}
saveNowInternal(persistable);
} catch (Throwable e) {
log.error("Error during saveFileTask", e);
}
return null;
};
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
UserThread.execute(FileManager.this::shutDown);
}, "FileManager.ShutDownHook"));
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
/**
* Actually write the wallet file to disk, using an atomic rename when possible. Runs on the current thread.
*/
public void saveNow(T persistable) {
saveNowInternal(persistable);
}
/**
* Queues up a save in the background. Useful for not very important wallet changes.
*/
public void saveLater(T persistable) {
saveLater(persistable, delay);
}
public void saveLater(T persistable, long delayInMilli) {
this.persistable = persistable;
if (savePending.getAndSet(true))
return; // Already pending.
executor.schedule(saveFileTask, delayInMilli, TimeUnit.MILLISECONDS);
}
@SuppressWarnings("unchecked")
public synchronized T read(File file) {
log.debug("Read from disc: {}", file.getName());
try (final FileInputStream fileInputStream = new FileInputStream(file)) {
PB.PersistableEnvelope persistable = PB.PersistableEnvelope.parseDelimitedFrom(fileInputStream);
return (T) persistenceProtoResolver.fromProto(persistable);
} catch (Throwable t) {
String errorMsg = "Exception at proto read: " + t.getMessage() + " file:" + file.getAbsolutePath();
log.error(errorMsg, t);
//if(DevEnv.DEV_MODE)
throw new RuntimeException(errorMsg);
}
}
public synchronized void removeFile(String fileName) {
log.debug("removeFile" + fileName);
File file = new File(dir, fileName);
boolean result = file.delete();
if (!result)
log.warn("Could not delete file: " + file.toString());
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
if (backupDir.exists()) {
File backupFile = new File(Paths.get(dir.getAbsolutePath(), "backup", fileName).toString());
if (backupFile.exists()) {
result = backupFile.delete();
if (!result)
log.warn("Could not delete backupFile: " + file.toString());
}
}
}
/**
* Shut down auto-saving.
*/
void shutDown() {
executor.shutdown();
try {
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
public synchronized void removeAndBackupFile(String fileName) throws IOException {
File corruptedBackupDir = new File(Paths.get(dir.getAbsolutePath(), "backup_of_corrupted_data").toString());
if (!corruptedBackupDir.exists())
if (!corruptedBackupDir.mkdir())
log.warn("make dir failed");
File corruptedFile = new File(Paths.get(dir.getAbsolutePath(), "backup_of_corrupted_data", fileName).toString());
FileUtil.renameFile(storageFile, corruptedFile);
}
public synchronized void backupFile(String fileName, int numMaxBackupFiles) {
FileUtil.rollingBackup(dir, fileName, numMaxBackupFiles);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void saveNowInternal(T persistable) {
long now = System.currentTimeMillis();
saveToFile(persistable, dir, storageFile);
log.trace("Save {} completed in {} msec", storageFile, System.currentTimeMillis() - now);
}
private synchronized void saveToFile(T persistable, File dir, File storageFile) {
File tempFile = null;
FileOutputStream fileOutputStream = null;
PrintWriter printWriter = null;
try {
log.debug("Write to disc: {}", storageFile.getName());
PB.PersistableEnvelope protoPersistable;
try {
protoPersistable = (PB.PersistableEnvelope) persistable.toProtoMessage();
if (protoPersistable.toByteArray().length == 0)
log.error("protoPersistable is empty. persistable=" + persistable.getClass().getSimpleName());
} catch (Throwable e) {
log.error("Error in saveToFile toProtoMessage: {}, {}", persistable.getClass().getSimpleName(), storageFile);
e.printStackTrace();
throw new RuntimeException(e);
}
if (!dir.exists() && !dir.mkdir())
log.warn("make dir failed");
tempFile = File.createTempFile("temp", null, dir);
tempFile.deleteOnExit();
fileOutputStream = new FileOutputStream(tempFile);
log.debug("Writing protobuffer class:{} to file:{}", persistable.getClass(), storageFile.getName());
writeLock.lock();
protoPersistable.writeDelimitedTo(fileOutputStream);
// 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();
writeLock.unlock();
// Close resources before replacing file with temp file because otherwise it causes problems on windows
// when rename temp file
fileOutputStream.close();
FileUtil.renameFile(tempFile, storageFile);
} catch (Throwable t) {
log.error("Error at saveToFile, storageFile=" + storageFile.toString(), t);
} finally {
if (writeLock.isLocked())
writeLock.unlock();
if (tempFile != null && tempFile.exists()) {
log.warn("Temp file still exists after failed save. We will delete it now. storageFile=" + storageFile);
if (!tempFile.delete())
log.error("Cannot delete temp file.");
}
try {
if (fileOutputStream != null)
fileOutputStream.close();
//noinspection ConstantConditions,ConstantConditions
if (printWriter != null)
printWriter.close();
} catch (IOException e) {
// We swallow that
e.printStackTrace();
log.error("Cannot close resources." + e.getMessage());
}
}
}
}

View File

@ -1,165 +0,0 @@
package io.bisq.common.storage;
import com.google.common.io.Files;
import io.bisq.common.util.Utilities;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
public class FileUtil {
private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
public static void rollingBackup(File dir, String fileName, int numMaxBackupFiles) {
if (dir.exists()) {
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
if (!backupDir.exists())
if (!backupDir.mkdir())
log.warn("make dir failed.\nBackupDir=" + backupDir.getAbsolutePath());
File origFile = new File(Paths.get(dir.getAbsolutePath(), fileName).toString());
if (origFile.exists()) {
String dirName = "backups_" + fileName;
if (dirName.contains("."))
dirName = dirName.replace(".", "_");
File backupFileDir = new File(Paths.get(backupDir.getAbsolutePath(), dirName).toString());
if (!backupFileDir.exists())
if (!backupFileDir.mkdir())
log.warn("make backupFileDir failed.\nBackupFileDir=" + backupFileDir.getAbsolutePath());
File backupFile = new File(Paths.get(backupFileDir.getAbsolutePath(), new Date().getTime() + "_" + fileName).toString());
try {
Files.copy(origFile, backupFile);
pruneBackup(backupFileDir, numMaxBackupFiles);
} catch (IOException e) {
log.error("Backup key failed: " + e.getMessage());
e.printStackTrace();
}
}
}
}
private static void pruneBackup(File backupDir, int numMaxBackupFiles) {
if (backupDir.isDirectory()) {
File[] files = backupDir.listFiles();
if (files != null) {
List<File> filesList = Arrays.asList(files);
if (filesList.size() > numMaxBackupFiles) {
filesList.sort((o1, o2) -> o1.getName().compareTo(o2.getName()));
File file = filesList.get(0);
if (file.isFile()) {
if (!file.delete())
log.error("Failed to delete file: " + file);
else
pruneBackup(backupDir, numMaxBackupFiles);
} else {
pruneBackup(new File(Paths.get(backupDir.getAbsolutePath(), file.getName()).toString()), numMaxBackupFiles);
}
}
}
}
}
public static void deleteDirectory(File file) throws IOException {
deleteDirectory(file, null, true);
}
public static void deleteDirectory(File file, @Nullable File exclude, boolean ignoreLockedFiles) throws IOException {
boolean excludeFileFound = false;
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null)
for (File f : files) {
if (!excludeFileFound)
excludeFileFound = f.equals(exclude);
if (!f.equals(exclude))
deleteDirectory(f, exclude, ignoreLockedFiles);
}
}
// Finally delete main file/dir if exclude file was not found in directory
if (!excludeFileFound && !file.equals(exclude)) {
try {
deleteFileIfExists(file, ignoreLockedFiles);
} catch (Throwable t) {
log.error("Could not delete file. Error=" + t.toString());
throw new IOException(t);
}
}
}
public static void deleteFileIfExists(File file) throws IOException {
deleteFileIfExists(file, true);
}
public static void deleteFileIfExists(File file, boolean ignoreLockedFiles) throws IOException {
try {
if (Utilities.isWindows())
file = file.getCanonicalFile();
if (file.exists() && !file.delete()) {
if (ignoreLockedFiles) {
// We check if file is locked. On Windows all open files are locked by the OS, so we
if (isFileLocked(file))
log.info("Failed to delete locked file: " + file.getAbsolutePath());
} else {
final String message = "Failed to delete file: " + file.getAbsolutePath();
log.error(message);
throw new IOException(message);
}
}
} catch (Throwable t) {
log.error(t.toString());
t.printStackTrace();
throw new IOException(t);
}
}
private static boolean isFileLocked(File file) {
return !file.canWrite();
}
public static void resourceToFile(String resourcePath, File destinationFile) throws ResourceNotFoundException, IOException {
InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
if (inputStream == null)
throw new ResourceNotFoundException(resourcePath);
try (FileOutputStream fileOutputStream = new FileOutputStream(destinationFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, bytesRead);
}
}
}
public static void renameFile(File oldFile, File newFile) throws IOException {
if (Utilities.isWindows()) {
// Work around an issue on Windows whereby you can't rename over existing files.
final File canonical = newFile.getCanonicalFile();
if (canonical.exists() && !canonical.delete()) {
throw new IOException("Failed to delete canonical file for replacement with save");
}
if (!oldFile.renameTo(canonical)) {
throw new IOException("Failed to rename " + oldFile + " to " + canonical);
}
} else if (!oldFile.renameTo(newFile)) {
throw new IOException("Failed to rename " + oldFile + " to " + newFile);
}
}
public static void copyDirectory(File source, File destination) throws IOException {
FileUtils.copyDirectory(source, destination);
}
}

View File

@ -1,105 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.storage;
import io.bisq.common.UserThread;
import io.bisq.common.util.Utilities;
import lombok.extern.slf4j.Slf4j;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Slf4j
public class JsonFileManager {
private final ThreadPoolExecutor executor = Utilities.getThreadPoolExecutor("saveToDiscExecutor", 5, 50, 60);
private final File dir;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public JsonFileManager(File dir) {
this.dir = dir;
if (!dir.exists())
if (!dir.mkdir())
log.warn("make dir failed");
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
UserThread.execute(JsonFileManager.this::shutDown);
}, "WriteOnlyFileManager.ShutDownHook"));
}
public void shutDown() {
executor.shutdown();
try {
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
public void writeToDisc(String json, String fileName) {
executor.execute(() -> {
File jsonFile = new File(Paths.get(dir.getAbsolutePath(), fileName + ".json").toString());
File tempFile = null;
PrintWriter printWriter = null;
try {
tempFile = File.createTempFile("temp", null, dir);
if (!executor.isShutdown() && !executor.isTerminated() && !executor.isTerminating())
tempFile.deleteOnExit();
printWriter = new PrintWriter(tempFile);
printWriter.println(json);
FileUtil.renameFile(tempFile, jsonFile);
} catch (Throwable t) {
log.error("storageFile " + jsonFile.toString());
t.printStackTrace();
} finally {
if (tempFile != null && tempFile.exists()) {
log.warn("Temp file still exists after failed save. We will delete it now. storageFile=" + fileName);
if (!tempFile.delete())
log.error("Cannot delete temp file.");
}
if (printWriter != null)
printWriter.close();
}
});
}
public Object readJsonFromDisc(String fileName) {
final File jsonFile = new File(Paths.get(dir.getAbsolutePath(), fileName + ".json").toString());
JSONParser parser = new JSONParser();
try {
return parser.parse(new FileReader(jsonFile));
} catch (ParseException | IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}

View File

@ -1,7 +0,0 @@
package io.bisq.common.storage;
public class ResourceNotFoundException extends Exception {
public ResourceNotFoundException(String path) {
super("Resource not found: path = " + path);
}
}

View File

@ -1,179 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.storage;
import com.google.inject.Inject;
import io.bisq.common.proto.persistable.PersistableEnvelope;
import io.bisq.common.proto.persistable.PersistenceProtoResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.inject.Named;
import java.io.File;
import java.io.IOException;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* That class handles the storage of a particular object to disk using Protobuffer.
* <p/>
* For every data object we write a separate file to minimize the risk of corrupted files in case of inconsistency from newer versions.
* In case of a corrupted file we backup the old file to a separate directory, so if it holds critical data it might be helpful for recovery.
* <p/>
* We also backup at first read the file, so we have a valid file form the latest version in case a write operation corrupted the file.
* <p/>
* The read operation is triggered just at object creation (startup) and is at the moment not executed on a background thread to avoid asynchronous behaviour.
* As the data are small and it is just one read access the performance penalty is small and might be even worse to create and setup a thread for it.
* <p/>
* The write operation used a background thread and supports a delayed write to avoid too many repeated write operations.
*/
public class Storage<T extends PersistableEnvelope> {
private static final Logger log = LoggerFactory.getLogger(Storage.class);
public static final String STORAGE_DIR = "storageDir";
private static DataBaseCorruptionHandler databaseCorruptionHandler;
public static void setDatabaseCorruptionHandler(DataBaseCorruptionHandler databaseCorruptionHandler) {
Storage.databaseCorruptionHandler = databaseCorruptionHandler;
}
public interface DataBaseCorruptionHandler {
void onFileCorrupted(String fileName);
}
private final File dir;
private FileManager<T> fileManager;
private File storageFile;
private T persistable;
private String fileName;
private int numMaxBackupFiles = 10;
private final PersistenceProtoResolver persistenceProtoResolver;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public Storage(@Named(STORAGE_DIR) File dir, PersistenceProtoResolver persistenceProtoResolver) {
this.dir = dir;
this.persistenceProtoResolver = persistenceProtoResolver;
}
@Nullable
public T initAndGetPersistedWithFileName(String fileName, long delay) {
this.fileName = fileName;
storageFile = new File(dir, fileName);
fileManager = new FileManager<>(dir, storageFile, delay, persistenceProtoResolver);
return getPersisted();
}
@Nullable
public T initAndGetPersisted(T persistable, long delay) {
return initAndGetPersisted(persistable, persistable.getClass().getSimpleName(), delay);
}
@Nullable
public T initAndGetPersisted(T persistable, String fileName, long delay) {
this.persistable = persistable;
this.fileName = fileName;
storageFile = new File(dir, fileName);
fileManager = new FileManager<>(dir, storageFile, delay, persistenceProtoResolver);
return getPersisted();
}
public void queueUpForSave() {
queueUpForSave(persistable);
}
public void queueUpForSave(long delayInMilli) {
queueUpForSave(persistable, delayInMilli);
}
public void setNumMaxBackupFiles(int numMaxBackupFiles) {
this.numMaxBackupFiles = numMaxBackupFiles;
}
// Save delayed and on a background thread
public void queueUpForSave(T persistable) {
if (persistable != null) {
log.trace("save " + fileName);
checkNotNull(storageFile, "storageFile = null. Call setupFileStorage before using read/write.");
fileManager.saveLater(persistable);
} else {
log.trace("queueUpForSave called but no persistable set");
}
}
public void queueUpForSave(T persistable, long delayInMilli) {
if (persistable != null) {
log.trace("save " + fileName);
checkNotNull(storageFile, "storageFile = null. Call setupFileStorage before using read/write.");
fileManager.saveLater(persistable, delayInMilli);
} else {
log.trace("queueUpForSave called but no persistable set");
}
}
public void remove(String fileName) {
fileManager.removeFile(fileName);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
// We do the file read on the UI thread to avoid problems from multi threading.
// Data are small and read is done only at startup, so it is no performance issue.
@Nullable
private T getPersisted() {
if (storageFile.exists()) {
long now = System.currentTimeMillis();
try {
T persistedObject = fileManager.read(storageFile);
log.trace("Read {} completed in {}msec", storageFile, System.currentTimeMillis() - now);
// If we did not get any exception we can be sure the data are consistent so we make a backup
now = System.currentTimeMillis();
fileManager.backupFile(fileName, numMaxBackupFiles);
log.trace("Backup {} completed in {}msec", storageFile, System.currentTimeMillis() - now);
return persistedObject;
} catch (Throwable t) {
log.error("We cannot read the persisted data. " +
"We make a backup and remove the inconsistent file. fileName=" + fileName);
log.error(t.getMessage());
try {
// We keep a backup which might be used for recovery
fileManager.removeAndBackupFile(fileName);
} catch (IOException e1) {
e1.printStackTrace();
log.error(e1.getMessage());
// We swallow Exception if backup fails
}
if (databaseCorruptionHandler != null)
databaseCorruptionHandler.onFileCorrupted(storageFile.getName());
}
}
return null;
}
}

View File

@ -1,24 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.taskrunner;
public class InterceptTaskException extends RuntimeException {
public InterceptTaskException(String message) {
super(message);
}
}

View File

@ -1,24 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.taskrunner;
public interface Model {
void persist();
void onComplete();
}

View File

@ -1,77 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.taskrunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class Task<T extends Model> {
private static final Logger log = LoggerFactory.getLogger(Task.class);
public static Class<? extends Task> taskToIntercept;
private final TaskRunner taskHandler;
protected final T model;
protected String errorMessage = "An error occurred at task: " + getClass().getSimpleName();
protected boolean completed;
public Task(TaskRunner taskHandler, T model) {
this.taskHandler = taskHandler;
this.model = model;
}
abstract protected void run();
protected void runInterceptHook() {
if (getClass() == taskToIntercept)
throw new InterceptTaskException("Task intercepted for testing purpose. Task = " + getClass().getSimpleName());
}
protected void appendToErrorMessage(String message) {
errorMessage += "\n" + message;
}
protected void appendExceptionToErrorMessage(Throwable t) {
if (t.getMessage() != null)
errorMessage += "\nException message: " + t.getMessage();
else
errorMessage += "\nException: " + t.toString();
}
protected void complete() {
completed = true;
taskHandler.handleComplete();
}
protected void failed(String message) {
appendToErrorMessage(message);
failed();
}
protected void failed(Throwable t) {
t.printStackTrace();
appendExceptionToErrorMessage(t);
failed();
}
protected void failed() {
log.error(errorMessage);
taskHandler.handleErrorMessage(errorMessage);
}
}

View File

@ -1,94 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.taskrunner;
import io.bisq.common.handlers.ErrorMessageHandler;
import io.bisq.common.handlers.ResultHandler;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
@Slf4j
public class TaskRunner<T extends Model> {
private final Queue<Class<? extends Task>> tasks = new LinkedBlockingQueue<>();
private final T sharedModel;
private final Class<T> sharedModelClass;
private final ResultHandler resultHandler;
private final ErrorMessageHandler errorMessageHandler;
private boolean failed = false;
private boolean isCanceled;
private Class<? extends Task> currentTask;
public TaskRunner(T sharedModel, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
//noinspection unchecked
this(sharedModel, (Class<T>) sharedModel.getClass(), resultHandler, errorMessageHandler);
}
public TaskRunner(T sharedModel, Class<T> sharedModelClass, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
this.sharedModel = sharedModel;
this.resultHandler = resultHandler;
this.errorMessageHandler = errorMessageHandler;
this.sharedModelClass = sharedModelClass;
}
@SafeVarargs
public final void addTasks(Class<? extends Task<T>>... items) {
tasks.addAll(Arrays.asList(items));
}
public void run() {
next();
}
private void next() {
if (!failed && !isCanceled) {
if (tasks.size() > 0) {
try {
currentTask = tasks.poll();
log.info("Run task: " + currentTask.getSimpleName());
currentTask.getDeclaredConstructor(TaskRunner.class, sharedModelClass).newInstance(this, sharedModel).run();
} catch (Throwable throwable) {
throwable.printStackTrace();
handleErrorMessage("Error at taskRunner: " + throwable.getMessage());
}
} else {
resultHandler.handleResult();
}
}
}
public void cancel() {
isCanceled = true;
}
void handleComplete() {
log.trace("Task completed: " + currentTask.getSimpleName());
sharedModel.persist();
next();
}
void handleErrorMessage(String errorMessage) {
log.error("Task failed: " + currentTask.getSimpleName() + " / errorMessage: " + errorMessage);
failed = true;
errorMessageHandler.handleErrorMessage(errorMessage);
}
}

View File

@ -1,240 +0,0 @@
package io.bisq.common.util;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
// Taken form https://stackoverflow.com/questions/18004150/desktop-api-is-not-supported-on-the-current-platform,
// originally net.mightypork.rpack.utils.DesktopApi
class DesktopUtil {
public static boolean browse(URI uri) {
return openSystemSpecific(uri.toString()) || browseDESKTOP(uri);
}
public static boolean open(File file) {
return openSystemSpecific(file.getPath()) || openDESKTOP(file);
}
public static boolean edit(File file) {
// you can try something like
// runCommand("gimp", "%s", file.getPath())
// based on user preferences.
return openSystemSpecific(file.getPath()) || editDESKTOP(file);
}
private static boolean openSystemSpecific(String what) {
EnumOS os = getOs();
if (os.isLinux()) {
if (runCommand("kde-open", "%s", what)) return true;
if (runCommand("gnome-open", "%s", what)) return true;
if (runCommand("xdg-open", "%s", what)) return true;
}
if (os.isMac()) {
if (runCommand("open", "%s", what)) return true;
}
if (os.isWindows()) {
if (runCommand("explorer", "%s", what)) return true;
}
return false;
}
private static boolean browseDESKTOP(URI uri) {
logOut("Trying to use Desktop.getDesktop().browse() with " + uri.toString());
try {
if (!Desktop.isDesktopSupported()) {
logErr("Platform is not supported.");
return false;
}
if (!Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
logErr("BROWSE is not supported.");
return false;
}
Desktop.getDesktop().browse(uri);
return true;
} catch (Throwable t) {
logErr("Error using desktop browse.", t);
return false;
}
}
private static boolean openDESKTOP(File file) {
logOut("Trying to use Desktop.getDesktop().open() with " + file.toString());
try {
if (!Desktop.isDesktopSupported()) {
logErr("Platform is not supported.");
return false;
}
if (!Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) {
logErr("OPEN is not supported.");
return false;
}
Desktop.getDesktop().open(file);
return true;
} catch (Throwable t) {
logErr("Error using desktop open.", t);
return false;
}
}
private static boolean editDESKTOP(File file) {
logOut("Trying to use Desktop.getDesktop().edit() with " + file);
try {
if (!Desktop.isDesktopSupported()) {
logErr("Platform is not supported.");
return false;
}
if (!Desktop.getDesktop().isSupported(Desktop.Action.EDIT)) {
logErr("EDIT is not supported.");
return false;
}
Desktop.getDesktop().edit(file);
return true;
} catch (Throwable t) {
logErr("Error using desktop edit.", t);
return false;
}
}
@SuppressWarnings("SameParameterValue")
private static boolean runCommand(String command, String args, String file) {
logOut("Trying to exec:\n cmd = " + command + "\n args = " + args + "\n %s = " + file);
String[] parts = prepareCommand(command, args, file);
try {
Process p = Runtime.getRuntime().exec(parts);
if (p == null) return false;
try {
int value = p.exitValue();
if (value == 0) {
logErr("Process ended immediately.");
return false;
} else {
logErr("Process crashed.");
return false;
}
} catch (IllegalThreadStateException e) {
logErr("Process is running.");
return true;
}
} catch (IOException e) {
logErr("Error running command.", e);
return false;
}
}
private static String[] prepareCommand(String command, String args, String file) {
List<String> parts = new ArrayList<>();
parts.add(command);
if (args != null) {
for (String s : args.split(" ")) {
s = String.format(s, file); // put in the filename thing
parts.add(s.trim());
}
}
return parts.toArray(new String[parts.size()]);
}
private static void logErr(String msg, Throwable t) {
System.err.println(msg);
t.printStackTrace();
}
private static void logErr(String msg) {
System.err.println(msg);
}
private static void logOut(String msg) {
System.out.println(msg);
}
public enum EnumOS {
linux,
macos,
solaris,
unknown,
windows;
public boolean isLinux() {
return this == linux || this == solaris;
}
public boolean isMac() {
return this == macos;
}
public boolean isWindows() {
return this == windows;
}
}
private static EnumOS getOs() {
String s = System.getProperty("os.name").toLowerCase();
if (s.contains("win")) {
return EnumOS.windows;
}
if (s.contains("mac")) {
return EnumOS.macos;
}
if (s.contains("solaris")) {
return EnumOS.solaris;
}
if (s.contains("sunos")) {
return EnumOS.solaris;
}
if (s.contains("linux")) {
return EnumOS.linux;
}
if (s.contains("unix")) {
return EnumOS.linux;
} else {
return EnumOS.unknown;
}
}
}

View File

@ -1,70 +0,0 @@
package io.bisq.common.util;
import lombok.Getter;
import java.util.concurrent.Callable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier;
public class FunctionalReadWriteLock {
@Getter
private final Lock readLock;
@Getter
private final Lock writeLock;
public FunctionalReadWriteLock(boolean isFair) {
this(new ReentrantReadWriteLock(isFair));
}
private FunctionalReadWriteLock(ReadWriteLock lock) {
readLock = lock.readLock();
writeLock = lock.writeLock();
}
public <T> T read(Supplier<T> block) {
readLock.lock();
try {
return block.get();
} finally {
readLock.unlock();
}
}
public void read(Runnable block) {
readLock.lock();
try {
block.run();
} finally {
readLock.unlock();
}
}
public <T> T write(Supplier<T> block) {
writeLock.lock();
try {
return block.get();
} finally {
writeLock.unlock();
}
}
public void write(Runnable block) {
writeLock.lock();
try {
block.run();
} finally {
writeLock.unlock();
}
}
public void write2(Callable block) throws Exception {
writeLock.lock();
try {
block.call();
} finally {
writeLock.unlock();
}
}
}

View File

@ -1,28 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonExclude {
}

View File

@ -1,77 +0,0 @@
package io.bisq.common.util;
import com.google.common.math.DoubleMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class MathUtils {
private static final Logger log = LoggerFactory.getLogger(MathUtils.class);
public static double roundDouble(double value, int precision) {
return roundDouble(value, precision, RoundingMode.HALF_UP);
}
@SuppressWarnings("SameParameterValue")
public static double roundDouble(double value, int precision, RoundingMode roundingMode) {
if (precision < 0)
throw new IllegalArgumentException();
try {
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(precision, roundingMode);
return bd.doubleValue();
} catch (Throwable t) {
log.error(t.toString());
return 0;
}
}
public static long roundDoubleToLong(double value) {
return roundDoubleToLong(value, RoundingMode.HALF_UP);
}
@SuppressWarnings("SameParameterValue")
public static long roundDoubleToLong(double value, RoundingMode roundingMode) {
return DoubleMath.roundToLong(value, roundingMode);
}
public static int roundDoubleToInt(double value) {
return roundDoubleToInt(value, RoundingMode.HALF_UP);
}
@SuppressWarnings("SameParameterValue")
public static int roundDoubleToInt(double value, RoundingMode roundingMode) {
return DoubleMath.roundToInt(value, roundingMode);
}
public static long doubleToLong(double value) {
return new Double(value).longValue();
}
public static double scaleUpByPowerOf10(double value, int exponent) {
double factor = Math.pow(10, exponent);
return value * factor;
}
public static double scaleUpByPowerOf10(long value, int exponent) {
double factor = Math.pow(10, exponent);
return ((double) value) * factor;
}
public static double scaleDownByPowerOf10(double value, int exponent) {
double factor = Math.pow(10, exponent);
return value / factor;
}
public static double scaleDownByPowerOf10(long value, int exponent) {
double factor = Math.pow(10, exponent);
return ((double) value) / factor;
}
public static double exactMultiply(double value1, double value2) {
return BigDecimal.valueOf(value1).multiply(BigDecimal.valueOf(value2)).doubleValue();
}
}

View File

@ -1,38 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.util;
import org.slf4j.Logger;
public class Profiler {
public static void printSystemLoad(Logger log) {
log.info(printSystemLoadString());
}
public static String printSystemLoadString() {
return "System load: Memory (MB)): " + getUsedMemoryInMB() + " / No. of threads: " + Thread.activeCount();
}
public static long getUsedMemoryInMB() {
Runtime runtime = Runtime.getRuntime();
long free = runtime.freeMemory() / 1024 / 1024;
long total = runtime.totalMemory() / 1024 / 1024;
return total - free;
}
}

View File

@ -1,65 +0,0 @@
package io.bisq.common.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.List;
// Borrowed from: https://dzone.com/articles/programmatically-restart-java
public class RestartUtil {
private static final Logger log = LoggerFactory.getLogger(RestartUtil.class);
/**
* Sun property pointing the main class and its arguments.
* Might not be defined on non Hotspot VM implementations.
*/
public static final String SUN_JAVA_COMMAND = "sun.java.command";
public static void restartApplication(String logPath) throws IOException {
try {
String java = System.getProperty("java.home") + "/bin/java";
List<String> vmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
StringBuilder vmArgsOneLine = new StringBuilder();
// if it's the agent argument : we ignore it otherwise the
// address of the old application and the new one will be in conflict
vmArguments.stream().filter(arg -> !arg.contains("-agentlib")).forEach(arg -> {
vmArgsOneLine.append(arg);
vmArgsOneLine.append(" ");
});
// init the command to execute, add the vm args
final StringBuilder cmd = new StringBuilder(java + " " + vmArgsOneLine);
// program main and program arguments
String[] mainCommand = System.getProperty(SUN_JAVA_COMMAND).split(" ");
// program main is a jar
if (mainCommand[0].endsWith(".jar")) {
// if it's a jar, add -jar mainJar
cmd.append("-jar ").append(new File(mainCommand[0]).getPath());
} else {
// else it's a .class, add the classpath and mainClass
cmd.append("-cp \"").append(System.getProperty("java.class.path")).append("\" ").append(mainCommand[0]);
}
// finally add program arguments
for (int i = 1; i < mainCommand.length; i++) {
cmd.append(" ");
cmd.append(mainCommand[i]);
}
try {
final String command = "nohup " + cmd.toString() + " >/dev/null 2>" + logPath + " &";
log.warn("\n\n############################################################\n" +
"Executing cmd for restart: {}" +
"\n############################################################\n\n",
command);
Runtime.getRuntime().exec(command);
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
throw new IOException("Error while trying to restart the application", e);
}
}
}

View File

@ -1,52 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.util;
import java.io.Serializable;
public class Tuple2<A, B> implements Serializable {
private static final long serialVersionUID = 1;
final public A first;
final public B second;
public Tuple2(A first, B second) {
this.first = first;
this.second = second;
}
@SuppressWarnings("SimplifiableIfStatement")
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Tuple2)) return false;
Tuple2<?, ?> tuple2 = (Tuple2<?, ?>) o;
if (first != null ? !first.equals(tuple2.first) : tuple2.first != null) return false;
return !(second != null ? !second.equals(tuple2.second) : tuple2.second != null);
}
@Override
public int hashCode() {
int result = first != null ? first.hashCode() : 0;
result = 31 * result + (second != null ? second.hashCode() : 0);
return result;
}
}

View File

@ -1,52 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.util;
public class Tuple3<A, B, C> {
final public A first;
final public B second;
final public C third;
public Tuple3(A first, B second, C third) {
this.first = first;
this.second = second;
this.third = third;
}
@SuppressWarnings("SimplifiableIfStatement")
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Tuple3)) return false;
Tuple3<?, ?, ?> tuple3 = (Tuple3<?, ?, ?>) o;
if (first != null ? !first.equals(tuple3.first) : tuple3.first != null) return false;
if (second != null ? !second.equals(tuple3.second) : tuple3.second != null) return false;
return !(third != null ? !third.equals(tuple3.third) : tuple3.third != null);
}
@Override
public int hashCode() {
int result = first != null ? first.hashCode() : 0;
result = 31 * result + (second != null ? second.hashCode() : 0);
result = 31 * result + (third != null ? third.hashCode() : 0);
return result;
}
}

View File

@ -1,56 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.util;
public class Tuple4<A, B, C, D> {
final public A first;
final public B second;
final public C third;
final public D forth;
public Tuple4(A first, B second, C third, D forth) {
this.first = first;
this.second = second;
this.third = third;
this.forth = forth;
}
@SuppressWarnings("SimplifiableIfStatement")
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Tuple4)) return false;
Tuple4<?, ?, ?, ?> tuple4 = (Tuple4<?, ?, ?, ?>) o;
if (first != null ? !first.equals(tuple4.first) : tuple4.first != null) return false;
if (second != null ? !second.equals(tuple4.second) : tuple4.second != null) return false;
if (third != null ? !third.equals(tuple4.third) : tuple4.third != null) return false;
return !(forth != null ? !forth.equals(tuple4.forth) : tuple4.forth != null);
}
@Override
public int hashCode() {
int result = first != null ? first.hashCode() : 0;
result = 31 * result + (second != null ? second.hashCode() : 0);
result = 31 * result + (third != null ? third.hashCode() : 0);
result = 31 * result + (forth != null ? forth.hashCode() : 0);
return result;
}
}

View File

@ -1,558 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.util;
import com.google.common.base.Splitter;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gson.*;
import io.bisq.common.crypto.LimitedKeyStrengthException;
import javafx.scene.input.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.bitcoinj.core.Utils;
import javax.annotation.Nullable;
import javax.crypto.Cipher;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.awt.Desktop.*;
@Slf4j
public class Utilities {
private static long lastTimeStamp = System.currentTimeMillis();
public static final String LB = System.getProperty("line.separator");
// TODO check out Jackson lib
public static String objectToJson(Object object) {
Gson gson = new GsonBuilder()
.setExclusionStrategies(new AnnotationExclusionStrategy())
/*.excludeFieldsWithModifiers(Modifier.TRANSIENT)*/
/* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)*/
.setPrettyPrinting()
.create();
return gson.toJson(object);
}
public static ListeningExecutorService getListeningSingleThreadExecutor(String name) {
return MoreExecutors.listeningDecorator(getSingleThreadExecutor(name));
}
public static ExecutorService getSingleThreadExecutor(String name) {
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(name)
.setDaemon(true)
.build();
return Executors.newSingleThreadExecutor(threadFactory);
}
public static ListeningExecutorService getListeningExecutorService(String name,
int corePoolSize,
int maximumPoolSize,
long keepAliveTimeInSec) {
return MoreExecutors.listeningDecorator(getThreadPoolExecutor(name, corePoolSize, maximumPoolSize, keepAliveTimeInSec));
}
public static ThreadPoolExecutor getThreadPoolExecutor(String name,
int corePoolSize,
int maximumPoolSize,
long keepAliveTimeInSec) {
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(name)
.setDaemon(true)
.build();
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTimeInSec,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(maximumPoolSize), threadFactory);
executor.allowCoreThreadTimeOut(true);
executor.setRejectedExecutionHandler((r, e) -> log.debug("RejectedExecutionHandler called"));
return executor;
}
@SuppressWarnings("SameParameterValue")
public static ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor(String name,
int corePoolSize,
int maximumPoolSize,
long keepAliveTimeInSec) {
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(name)
.setDaemon(true)
.setPriority(Thread.MIN_PRIORITY)
.build();
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
executor.setKeepAliveTime(keepAliveTimeInSec, TimeUnit.SECONDS);
executor.allowCoreThreadTimeOut(true);
executor.setMaximumPoolSize(maximumPoolSize);
executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
executor.setRejectedExecutionHandler((r, e) -> log.debug("RejectedExecutionHandler called"));
return executor;
}
public static boolean isUnix() {
return isOSX() || isLinux() || getOSName().contains("freebsd");
}
public static boolean isWindows() {
return getOSName().contains("win");
}
public static boolean isOSX() {
return getOSName().contains("mac") || getOSName().contains("darwin");
}
public static boolean isLinux() {
return getOSName().contains("linux");
}
private static String getOSName() {
return System.getProperty("os.name").toLowerCase(Locale.US);
}
public static String getOSArchitecture() {
String osArch = System.getProperty("os.arch");
if (isWindows()) {
// See: Like always windows needs extra treatment
// https://stackoverflow.com/questions/20856694/how-to-find-the-os-bit-type
String arch = System.getenv("PROCESSOR_ARCHITECTURE");
String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
return arch.endsWith("64")
|| wow64Arch != null && wow64Arch.endsWith("64")
? "64" : "32";
} else if (osArch.contains("arm")) {
// armv8 is 64 bit, armv7l is 32 bit
return osArch.contains("64") || osArch.contains("v8") ? "64" : "32";
} else if (isLinux()) {
return osArch.startsWith("i") ? "32" : "64";
} else {
return osArch.contains("64") ? "64" : osArch;
}
}
public static void printSysInfo() {
log.info("System info: os.name={}; os.version={}; os.arch={}; sun.arch.data.model={}; JRE={}; JVM={}",
System.getProperty("os.name"),
System.getProperty("os.version"),
System.getProperty("os.arch"),
getJVMArchitecture(),
(System.getProperty("java.runtime.version", "-") + " (" + System.getProperty("java.vendor", "-") + ")"),
(System.getProperty("java.vm.version", "-") + " (" + System.getProperty("java.vm.name", "-") + ")")
);
}
public static String getJVMArchitecture() {
return System.getProperty("sun.arch.data.model");
}
public static boolean isCorrectOSArchitecture() {
boolean result = getOSArchitecture().endsWith(getJVMArchitecture());
if (!result) {
log.warn("System.getProperty(\"os.arch\") " + System.getProperty("os.arch"));
log.warn("System.getenv(\"ProgramFiles(x86)\") " + System.getenv("ProgramFiles(x86)"));
log.warn("System.getenv(\"PROCESSOR_ARCHITECTURE\")" + System.getenv("PROCESSOR_ARCHITECTURE"));
log.warn("System.getenv(\"PROCESSOR_ARCHITEW6432\") " + System.getenv("PROCESSOR_ARCHITEW6432"));
log.warn("System.getProperty(\"sun.arch.data.model\") " + System.getProperty("sun.arch.data.model"));
}
return result;
}
public static void openURI(URI uri) throws IOException {
if (!isLinux()
&& isDesktopSupported()
&& getDesktop().isSupported(Action.BROWSE)) {
getDesktop().browse(uri);
} else {
// Maybe Application.HostServices works in those cases?
// HostServices hostServices = getHostServices();
// hostServices.showDocument(uri.toString());
// On Linux Desktop is poorly implemented.
// See https://stackoverflow.com/questions/18004150/desktop-api-is-not-supported-on-the-current-platform
if (!DesktopUtil.browse(uri))
throw new IOException("Failed to open URI: " + uri.toString());
}
}
public static void openFile(File file) throws IOException {
if (!isLinux()
&& isDesktopSupported()
&& getDesktop().isSupported(Action.OPEN)) {
getDesktop().open(file);
} else {
// Maybe Application.HostServices works in those cases?
// HostServices hostServices = getHostServices();
// hostServices.showDocument(uri.toString());
// On Linux Desktop is poorly implemented.
// See https://stackoverflow.com/questions/18004150/desktop-api-is-not-supported-on-the-current-platform
if (!DesktopUtil.open(file))
throw new IOException("Failed to open file: " + file.toString());
}
}
public static String getTmpDir() {
return System.getProperty("java.io.tmpdir");
}
public static String getDownloadOfHomeDir() {
File file = new File(getSystemHomeDirectory() + "/Downloads");
if (file.exists())
return file.getAbsolutePath();
else
return getSystemHomeDirectory();
}
public static void printSystemLoad() {
Runtime runtime = Runtime.getRuntime();
long free = runtime.freeMemory() / 1024 / 1024;
long total = runtime.totalMemory() / 1024 / 1024;
long used = total - free;
log.info("System load (no. threads/used memory (MB)): " + Thread.activeCount() + "/" + used);
}
public static void copyToClipboard(String content) {
try {
if (content != null && content.length() > 0) {
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.putString(content);
clipboard.setContent(clipboardContent);
}
} catch (Throwable e) {
log.error("copyToClipboard failed " + e.getMessage());
e.printStackTrace();
}
}
public static byte[] concatByteArrays(byte[]... arrays) {
int totalLength = 0;
for (byte[] array : arrays) {
totalLength += array.length;
}
byte[] result = new byte[totalLength];
int currentIndex = 0;
for (byte[] array : arrays) {
System.arraycopy(array, 0, result, currentIndex, array.length);
currentIndex += array.length;
}
return result;
}
public static <T> T jsonToObject(String jsonString, Class<T> classOfT) {
Gson gson =
new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).setPrettyPrinting().create();
return gson.fromJson(jsonString, classOfT);
}
public static <T extends Serializable> T deserialize(byte[] data) {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInput in = null;
Object result = null;
try {
in = new ObjectInputStream(bis);
result = in.readObject();
if (!(result instanceof Serializable))
throw new RuntimeException("Object not of type Serializable");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bis.close();
} catch (IOException ex) {
// ignore close exception
}
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
}
//noinspection unchecked,ConstantConditions
return (T) result;
}
public static byte[] serialize(Serializable object) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
byte[] result = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(object);
out.flush();
result = bos.toByteArray().clone();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException ignore) {
}
try {
bos.close();
} catch (IOException ignore) {
}
}
return result;
}
public static <T extends Serializable> T cloneObject(Serializable object) {
return deserialize(serialize(object));
}
@SuppressWarnings("SameParameterValue")
private static void printElapsedTime(String msg) {
if (!msg.isEmpty()) {
msg += " / ";
}
long timeStamp = System.currentTimeMillis();
log.debug(msg + "Elapsed: " + String.valueOf(timeStamp - lastTimeStamp));
lastTimeStamp = timeStamp;
}
public static void printElapsedTime() {
printElapsedTime("");
}
public static void setThreadName(String name) {
Thread.currentThread().setName(name + "-" + new Random().nextInt(10000));
}
public static boolean isDirectory(String path) {
return new File(path).isDirectory();
}
public static String getSystemHomeDirectory() {
return Utilities.isWindows() ? System.getenv("USERPROFILE") : System.getProperty("user.home");
}
public static String encodeToHex(@Nullable byte[] bytes, boolean allowNullable) {
if (allowNullable)
return bytes != null ? Utils.HEX.encode(bytes) : "null";
else
return Utils.HEX.encode(checkNotNull(bytes, "bytes must not be null at encodeToHex"));
}
public static String bytesAsHexString(@Nullable byte[] bytes) {
return encodeToHex(bytes, true);
}
public static String encodeToHex(@Nullable byte[] bytes) {
return encodeToHex(bytes, false);
}
public static byte[] decodeFromHex(String encoded) {
return Utils.HEX.decode(encoded);
}
public static boolean isAltOrCtrlPressed(KeyCode keyCode, KeyEvent keyEvent) {
return isAltPressed(keyCode, keyEvent) || isCtrlPressed(keyCode, keyEvent);
}
public static boolean isCtrlPressed(KeyCode keyCode, KeyEvent keyEvent) {
return new KeyCodeCombination(keyCode, KeyCombination.SHORTCUT_DOWN).match(keyEvent) ||
new KeyCodeCombination(keyCode, KeyCombination.CONTROL_DOWN).match(keyEvent);
}
public static boolean isAltPressed(KeyCode keyCode, KeyEvent keyEvent) {
return new KeyCodeCombination(keyCode, KeyCombination.ALT_DOWN).match(keyEvent);
}
public static byte[] concatenateByteArrays(byte[] array1, byte[] array2) {
return ArrayUtils.addAll(array1, array2);
}
public static byte[] concatenateByteArrays(byte[] array1, byte[] array2, byte[] array3) {
return ArrayUtils.addAll(array1, ArrayUtils.addAll(array2, array3));
}
public static byte[] concatenateByteArrays(byte[] array1, byte[] array2, byte[] array3, byte[] array4) {
return ArrayUtils.addAll(array1, ArrayUtils.addAll(array2, ArrayUtils.addAll(array3, array4)));
}
public static byte[] concatenateByteArrays(byte[] array1, byte[] array2, byte[] array3, byte[] array4, byte[] array5) {
return ArrayUtils.addAll(array1, ArrayUtils.addAll(array2, ArrayUtils.addAll(array3, ArrayUtils.addAll(array4, array5))));
}
public static Date getUTCDate(int year, int month, int dayOfMonth) {
GregorianCalendar calendar = new GregorianCalendar(year, month, dayOfMonth);
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
return calendar.getTime();
}
/**
* @param stringList String of comma separated tokens.
* @param allowWhitespace If white space inside the list tokens is allowed. If not the token will be ignored.
* @return Set of tokens
*/
public static Set<String> commaSeparatedListToSet(String stringList, boolean allowWhitespace) {
if (stringList != null) {
return Splitter.on(",")
.splitToList(allowWhitespace ? stringList : StringUtils.deleteWhitespace(stringList))
.stream()
.filter(e -> !e.isEmpty())
.collect(Collectors.toSet());
} else {
return new HashSet<>();
}
}
private static class AnnotationExclusionStrategy implements ExclusionStrategy {
@Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getAnnotation(JsonExclude.class) != null;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}
public static void checkCryptoPolicySetup() throws NoSuchAlgorithmException, LimitedKeyStrengthException {
if (Cipher.getMaxAllowedKeyLength("AES") > 128)
log.debug("Congratulations, you have unlimited key length support!");
else
throw new LimitedKeyStrengthException();
}
public static String toTruncatedString(Object message, int maxLength) {
if (message != null) {
return StringUtils.abbreviate(message.toString(), maxLength).replace("\n", "");
}
return "null";
}
public static String toTruncatedString(Object message) {
return toTruncatedString(message, 200);
}
public static String getRandomPrefix(int minLength, int maxLength) {
int length = minLength + new Random().nextInt(maxLength - minLength + 1);
String result;
switch (new Random().nextInt(3)) {
case 0:
result = RandomStringUtils.randomAlphabetic(length);
break;
case 1:
result = RandomStringUtils.randomNumeric(length);
break;
case 2:
default:
result = RandomStringUtils.randomAlphanumeric(length);
}
switch (new Random().nextInt(3)) {
case 0:
result = result.toUpperCase();
break;
case 1:
result = result.toLowerCase();
break;
case 2:
default:
}
return result;
}
public static String getShortId(String id) {
return getShortId(id, "-");
}
@SuppressWarnings("SameParameterValue")
public static String getShortId(String id, String sep) {
String[] chunks = id.split(sep);
if (chunks.length > 0)
return chunks[0];
else
return id.substring(0, Math.min(8, id.length()));
}
@SuppressWarnings("unchecked")
public static String collectionToCSV(Collection collection) {
return collection.stream().map(Object::toString).collect(Collectors.joining(",")).toString();
}
public static void removeCryptographyRestrictions() {
if (!isRestrictedCryptography()) {
System.out.println("Cryptography restrictions removal not needed");
return;
}
try {
/*
* Do the following, but with reflection to bypass access checks:
*
* JceSecurity.isRestricted = false;
* JceSecurity.defaultPolicy.perms.clear();
* JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
*/
final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
isRestrictedField.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
isRestrictedField.set(null, false);
final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
defaultPolicyField.setAccessible(true);
final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);
final Field perms = cryptoPermissions.getDeclaredField("perms");
perms.setAccessible(true);
((Map<?, ?>) perms.get(defaultPolicy)).clear();
final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
instance.setAccessible(true);
defaultPolicy.add((Permission) instance.get(null));
System.out.println("Successfully removed cryptography restrictions");
} catch (final Exception e) {
System.err.println("Failed to remove cryptography restrictions" + e);
}
}
public static boolean isRestrictedCryptography() {
// This matches Oracle Java 7 and 8, but not Java 9 or OpenJDK.
final String name = System.getProperty("java.runtime.name");
final String ver = System.getProperty("java.version");
return name != null && name.equals("Java(TM) SE Runtime Environment")
&& ver != null && (ver.startsWith("1.7") || ver.startsWith("1.8"));
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%highlight(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{15}: %msg %xEx%n)</pattern>
</encoder>
</appender>
<root level="TRACE">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>
<!-- <logger name="io.bisq.core.storage.Storage" level="WARN"/>
<logger name="io.bisq.core.storage.FileManager" level="WARN"/>
<logger name="io.bisq.locale.BSResources" level="ERROR"/>-->
<!-- <logger name="io.bisq.p2p.peers.PeerGroup" level="TRACE"/>
<logger name="io.bisq.p2p.P2PService" level="TRACE"/>
<logger name="io.bisq.p2p.storage.ProtectedExpirableDataStorage" level="TRACE"/>
<logger name="io.bisq.p2p.network.LocalhostNetworkNode" level="TRACE"/>
<logger name="io.bisq.p2p.network.TorNetworkNode" level="TRACE"/>
<logger name="io.bisq.p2p.network.NetworkNode" level="TRACE"/>-->
<!-- <logger name="com.msopentech.thali.toronionproxy.OnionProxyManagerEventHandler" level="WARN"/>
<logger name="io.bisq.btc.AddressBasedCoinSelector" level="WARN"/>
<logger name="io.bisq.storage.Storage" level="WARN"/>
<logger name="io.bisq.gui.util.Profiler" level="ERROR"/>
<logger name="io.bisq.temp.storage.RemoteStorage" level="WARN"/>
<logger name="io.bisq.storage.FileManager" level="WARN"/>
<logger name="org.bitcoinj" level="WARN"/>
<logger name="org.bitcoinj.core.BitcoinSerializer" level="WARN"/>
<logger name="org.bitcoinj.core.Peer" level="WARN"/>
<logger name="org.bitcoinj.core.HeadersMessage" level="WARN"/>
<logger name="org.bitcoinj.core.AbstractBlockChain" level="ERROR"/>-->
<!-- <logger name="com.msopentech.thali.toronionproxy.OnionProxyManagerEventHandler" level="INFO"/>
<logger name="org.bitcoinj" level="WARN"/>-->
</configuration>

View File

@ -1,55 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.app;
import org.junit.Test;
import java.util.Arrays;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class CapabilitiesTest {
@Test
public void testVersionNumber() {
// if required are null or empty its true
assertTrue(Capabilities.isCapabilitySupported(null, null));
assertTrue(Capabilities.isCapabilitySupported(null, Arrays.asList()));
assertTrue(Capabilities.isCapabilitySupported(null, Arrays.asList(0)));
assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(), null));
assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(), Arrays.asList()));
assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(), Arrays.asList(0)));
// required are not null and not empty but supported is null or empty its false
assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0), null));
assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList()));
// single match
assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList(0)));
assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(1), Arrays.asList(0)));
assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList(1)));
// multi match
assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList(0, 1)));
assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList(1, 2)));
assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(0, 1), Arrays.asList(0, 1)));
assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(0, 1), Arrays.asList(1,0)));
assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0, 1), Arrays.asList(0)));
}
}

View File

@ -1,51 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bisq.common.app;
import org.junit.Test;
import static org.junit.Assert.*;
public class VersionTest {
@Test
public void testVersionNumber() {
assertEquals(0, Version.getMajorVersion("0.0.0"));
assertEquals(1, Version.getMajorVersion("1.0.0"));
assertEquals(0, Version.getMinorVersion("0.0.0"));
assertEquals(5, Version.getMinorVersion("0.5.0"));
assertEquals(0, Version.getPatchVersion("0.0.0"));
assertEquals(5, Version.getPatchVersion("0.0.5"));
}
@Test
public void testIsNewVersion() {
assertFalse(Version.isNewVersion("0.0.0", "0.0.0"));
assertTrue(Version.isNewVersion("0.1.0", "0.0.0"));
assertTrue(Version.isNewVersion("0.0.1", "0.0.0"));
assertTrue(Version.isNewVersion("1.0.0", "0.0.0"));
assertTrue(Version.isNewVersion("0.5.1", "0.5.0"));
assertFalse(Version.isNewVersion("0.5.0", "0.5.1"));
assertTrue(Version.isNewVersion("0.6.0", "0.5.0"));
assertTrue(Version.isNewVersion("0.6.0", "0.5.1"));
assertFalse(Version.isNewVersion("0.5.0", "1.5.0"));
assertFalse(Version.isNewVersion("0.4.9", "0.5.0"));
}
}

View File

@ -1,30 +0,0 @@
package io.bisq.common.locale;
import org.junit.Before;
import org.junit.Test;
import java.util.Locale;
import java.util.Optional;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class CurrencyUtilTest {
@Before
public void setup() {
Locale.setDefault(new Locale("en", "US"));
}
@Test
public void testGetTradeCurrency() {
Optional<TradeCurrency> euro = CurrencyUtil.getTradeCurrency("EUR");
Optional<TradeCurrency> naira = CurrencyUtil.getTradeCurrency("NGN");
Optional<TradeCurrency> fake = CurrencyUtil.getTradeCurrency("FAK");
assertTrue(euro.isPresent());
assertTrue(naira.isPresent());
assertFalse("Fake currency shouldn't exist",fake.isPresent());
}
}

Some files were not shown because too many files have changed in this diff Show More