Move duplicated code to super class

Signed-off-by: HenrikJannsen <boilingfrog@gmx.com>
This commit is contained in:
HenrikJannsen 2024-06-28 21:41:41 +07:00
parent ed5547ac97
commit 59f2df9f2f
No known key found for this signature in database
GPG Key ID: 02AA2BAE387C8307
4 changed files with 131 additions and 236 deletions

View File

@ -18,21 +18,30 @@
package bisq.core.app.misc; package bisq.core.app.misc;
import bisq.core.app.BisqExecutable; import bisq.core.app.BisqExecutable;
import bisq.core.app.TorSetup;
import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.BsqWalletService; import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.DaoSetup; import bisq.core.dao.DaoSetup;
import bisq.core.dao.monitoring.DaoStateMonitoringService;
import bisq.core.dao.node.full.RpcService; import bisq.core.dao.node.full.RpcService;
import bisq.core.offer.OpenOfferManager; import bisq.core.offer.OpenOfferManager;
import bisq.core.offer.bsq_swap.OpenBsqSwapOfferService; import bisq.core.offer.bsq_swap.OpenBsqSwapOfferService;
import bisq.core.payment.TradeLimits; import bisq.core.payment.TradeLimits;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.user.Cookie;
import bisq.core.user.CookieKey;
import bisq.core.user.User;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
import bisq.network.p2p.P2PServiceListener;
import bisq.network.p2p.peers.PeerManager;
import bisq.common.Timer;
import bisq.common.UserThread; import bisq.common.UserThread;
import bisq.common.app.AppModule; import bisq.common.app.AppModule;
import bisq.common.app.DevEnv; import bisq.common.app.DevEnv;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.config.Config; import bisq.common.config.Config;
import bisq.common.file.JsonFileManager; import bisq.common.file.JsonFileManager;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;
@ -41,6 +50,9 @@ import bisq.common.setup.GracefulShutDownHandler;
import bisq.common.util.Profiler; import bisq.common.util.Profiler;
import bisq.common.util.SingleThreadExecutorUtils; import bisq.common.util.SingleThreadExecutorUtils;
import com.google.inject.Key;
import com.google.inject.name.Names;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -51,10 +63,18 @@ public abstract class ExecutableForAppWithP2p extends BisqExecutable {
private static final long CHECK_MEMORY_PERIOD_SEC = 300; private static final long CHECK_MEMORY_PERIOD_SEC = 300;
protected static final long CHECK_SHUTDOWN_SEC = TimeUnit.HOURS.toSeconds(1); protected static final long CHECK_SHUTDOWN_SEC = TimeUnit.HOURS.toSeconds(1);
protected static final long SHUTDOWN_INTERVAL = TimeUnit.HOURS.toMillis(24); protected static final long SHUTDOWN_INTERVAL = TimeUnit.HOURS.toMillis(24);
private static final long CHECK_CONNECTION_LOSS_SEC = 30;
private volatile boolean stopped; private volatile boolean stopped;
private final long startTime = System.currentTimeMillis(); private final long startTime = System.currentTimeMillis();
private TradeLimits tradeLimits; private TradeLimits tradeLimits;
private AppSetupWithP2PAndDAO appSetupWithP2PAndDAO; private AppSetupWithP2PAndDAO appSetupWithP2PAndDAO;
protected P2PService p2PService;
protected DaoStateMonitoringService daoStateMonitoringService;
protected Cookie cookie;
private Timer checkConnectionLossTimer;
private Boolean preventPeriodicShutdownAtSeedNode;
public ExecutableForAppWithP2p(String fullName, String scriptName, String appName, String version) { public ExecutableForAppWithP2p(String fullName, String scriptName, String appName, String version) {
super(fullName, scriptName, appName, version); super(fullName, scriptName, appName, version);
@ -76,15 +96,69 @@ public abstract class ExecutableForAppWithP2p extends BisqExecutable {
super.applyInjector(); super.applyInjector();
appSetupWithP2PAndDAO = injector.getInstance(AppSetupWithP2PAndDAO.class); appSetupWithP2PAndDAO = injector.getInstance(AppSetupWithP2PAndDAO.class);
p2PService = injector.getInstance(P2PService.class);
cookie = injector.getInstance(User.class).getCookie();
// Pin that as it is used in PaymentMethods and verification in TradeStatistics // Pin that as it is used in PaymentMethods and verification in TradeStatistics
tradeLimits = injector.getInstance(TradeLimits.class); tradeLimits = injector.getInstance(TradeLimits.class);
daoStateMonitoringService = injector.getInstance(DaoStateMonitoringService.class);
preventPeriodicShutdownAtSeedNode = injector.getInstance(Key.get(boolean.class,
Names.named(Config.PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE)));
} }
@Override @Override
protected void startApplication() { protected void startApplication() {
cookie.getAsOptionalBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART).ifPresent(cleanTorDirAtRestart -> {
if (cleanTorDirAtRestart) {
injector.getInstance(TorSetup.class).cleanupTorFiles(() ->
cookie.remove(CookieKey.CLEAN_TOR_DIR_AT_RESTART),
log::error);
}
});
daoStateMonitoringService.addListener(new DaoStateMonitoringService.Listener() {
@Override
public void onCheckpointFailed() {
gracefulShutDown();
}
});
p2PService.addP2PServiceListener(new P2PServiceListener() {
@Override
public void onDataReceived() {
}
@Override
public void onNoSeedNodeAvailable() {
}
@Override
public void onNoPeersAvailable() {
}
@Override
public void onUpdatedDataReceived() {
}
@Override
public void onTorNodeReady() {
}
@Override
public void onHiddenServicePublished() {
ExecutableForAppWithP2p.this.onHiddenServicePublished();
}
});
appSetupWithP2PAndDAO.start(); appSetupWithP2PAndDAO.start();
} }
protected void onHiddenServicePublished() {
if (!preventPeriodicShutdownAtSeedNode) {
startShutDownInterval();
}
UserThread.runAfter(this::setupConnectionLossCheck, 60);
}
@Override @Override
protected void launchApplication() { protected void launchApplication() {
onApplicationLaunched(); onApplicationLaunched();
@ -95,10 +169,26 @@ public abstract class ExecutableForAppWithP2p extends BisqExecutable {
log.info("onSetupComplete"); log.info("onSetupComplete");
} }
///////////////////////////////////////////////////////////////////////////////////////////
// UncaughtExceptionHandler implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void handleUncaughtException(Throwable throwable, boolean doShutDown) {
if (throwable instanceof OutOfMemoryError || doShutDown) {
log.error("We got an OutOfMemoryError and shut down");
gracefulShutDown(() -> log.info("gracefulShutDown complete"));
}
}
// We don't use the gracefulShutDown implementation of the super class as we have a limited set of modules // We don't use the gracefulShutDown implementation of the super class as we have a limited set of modules
@Override @Override
public void gracefulShutDown(ResultHandler resultHandler) { public void gracefulShutDown(ResultHandler resultHandler) {
log.info("gracefulShutDown"); log.info("gracefulShutDown");
if (checkConnectionLossTimer != null) {
checkConnectionLossTimer.stop();
}
try { try {
if (injector != null) { if (injector != null) {
JsonFileManager.shutDownAllInstances(); JsonFileManager.shutDownAllInstances();
@ -216,4 +306,25 @@ public abstract class ExecutableForAppWithP2p extends BisqExecutable {
System.exit(1); System.exit(1);
}); });
} }
protected void setupConnectionLossCheck() {
// For dev testing (usually on BTC_REGTEST) we don't want to get the seed shut
// down as it is normal that the seed is the only actively running node.
if (Config.baseCurrencyNetwork() == BaseCurrencyNetwork.BTC_REGTEST) {
return;
}
if (checkConnectionLossTimer != null) {
return;
}
checkConnectionLossTimer = UserThread.runPeriodically(() -> {
if (injector.getInstance(PeerManager.class).getNumAllConnectionsLostEvents() > 1) {
// We set a flag to clear tor cache files at re-start. We cannot clear it now as Tor is used and
// that can cause problems.
injector.getInstance(User.class).getCookie().putAsBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART, true);
shutDown(this);
}
}, CHECK_CONNECTION_LOSS_SEC);
}
} }

View File

@ -19,41 +19,22 @@ package bisq.restapi;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.app.TorSetup;
import bisq.core.app.misc.ExecutableForAppWithP2p; import bisq.core.app.misc.ExecutableForAppWithP2p;
import bisq.core.dao.SignVerifyService; import bisq.core.dao.SignVerifyService;
import bisq.core.dao.governance.bond.reputation.BondedReputationRepository; import bisq.core.dao.governance.bond.reputation.BondedReputationRepository;
import bisq.core.dao.governance.bond.role.BondedRolesRepository; import bisq.core.dao.governance.bond.role.BondedRolesRepository;
import bisq.core.dao.state.DaoStateService; import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.DaoStateSnapshotService; import bisq.core.dao.state.DaoStateSnapshotService;
import bisq.core.user.Cookie;
import bisq.core.user.CookieKey;
import bisq.core.user.Preferences; import bisq.core.user.Preferences;
import bisq.core.user.User;
import bisq.network.p2p.P2PService;
import bisq.network.p2p.P2PServiceListener;
import bisq.network.p2p.peers.PeerManager;
import bisq.common.Timer;
import bisq.common.UserThread;
import bisq.common.app.Version; import bisq.common.app.Version;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.config.Config; import bisq.common.config.Config;
import bisq.common.handlers.ResultHandler;
import com.google.inject.Key;
import com.google.inject.name.Names;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
//todo not sure if the restart handling from seed nodes is required
@Slf4j @Slf4j
public class RestApi extends ExecutableForAppWithP2p { public class RestApi extends ExecutableForAppWithP2p {
private static final long CHECK_CONNECTION_LOSS_SEC = 30;
private Timer checkConnectionLossTime;
@Getter @Getter
private DaoStateService daoStateService; private DaoStateService daoStateService;
@Getter @Getter
@ -64,6 +45,8 @@ public class RestApi extends ExecutableForAppWithP2p {
private BondedRolesRepository bondedRolesRepository; private BondedRolesRepository bondedRolesRepository;
@Getter @Getter
private SignVerifyService signVerifyService; private SignVerifyService signVerifyService;
private DaoStateSnapshotService daoStateSnapshotService;
private Preferences preferences;
public RestApi() { public RestApi() {
super("Bisq Rest Api", "bisq_restapi", "bisq_restapi", Version.VERSION); super("Bisq Rest Api", "bisq_restapi", "bisq_restapi", Version.VERSION);
@ -80,113 +63,31 @@ public class RestApi extends ExecutableForAppWithP2p {
checkMemory(config, this); checkMemory(config, this);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// We continue with a series of synchronous execution tasks
///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
protected void applyInjector() { protected void applyInjector() {
super.applyInjector(); super.applyInjector();
injector.getInstance(DaoStateSnapshotService.class).setResyncDaoStateFromResourcesHandler(this::gracefulShutDown); preferences = injector.getInstance(Preferences.class);
daoStateService = injector.getInstance(DaoStateService.class);
accountAgeWitnessService = injector.getInstance(AccountAgeWitnessService.class);
bondedReputationRepository = injector.getInstance(BondedReputationRepository.class);
bondedRolesRepository = injector.getInstance(BondedRolesRepository.class);
signVerifyService = injector.getInstance(SignVerifyService.class);
daoStateSnapshotService = injector.getInstance(DaoStateSnapshotService.class);
} }
@Override @Override
protected void startApplication() { protected void startApplication() {
super.startApplication(); super.startApplication();
Cookie cookie = injector.getInstance(User.class).getCookie(); preferences.setUseFullModeDaoMonitor(false);
cookie.getAsOptionalBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART).ifPresent(cleanTorDirAtRestart -> { daoStateSnapshotService.setResyncDaoStateFromResourcesHandler(this::gracefulShutDown);
if (cleanTorDirAtRestart) {
injector.getInstance(TorSetup.class).cleanupTorFiles(() ->
cookie.remove(CookieKey.CLEAN_TOR_DIR_AT_RESTART),
log::error);
}
});
injector.getInstance(Preferences.class).setUseFullModeDaoMonitor(false);
daoStateService = injector.getInstance(DaoStateService.class);
accountAgeWitnessService = injector.getInstance(AccountAgeWitnessService.class);
bondedReputationRepository = injector.getInstance(BondedReputationRepository.class);
bondedRolesRepository = injector.getInstance(BondedRolesRepository.class);
signVerifyService = injector.getInstance(SignVerifyService.class);
injector.getInstance(P2PService.class).addP2PServiceListener(new P2PServiceListener() {
@Override
public void onDataReceived() {
// Do nothing
} }
@Override @Override
public void onNoSeedNodeAvailable() { protected void onHiddenServicePublished() {
// Do nothing super.onHiddenServicePublished();
}
@Override
public void onNoPeersAvailable() {
// Do nothing
}
@Override
public void onUpdatedDataReceived() {
// Do nothing
}
@Override
public void onTorNodeReady() {
// Do nothing
}
@Override
public void onHiddenServicePublished() {
boolean preventPeriodicShutdownAtSeedNode = injector.getInstance(Key.get(boolean.class,
Names.named(Config.PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE)));
if (!preventPeriodicShutdownAtSeedNode) {
startShutDownInterval();
}
UserThread.runAfter(() -> setupConnectionLossCheck(), 60);
accountAgeWitnessService.onAllServicesInitialized(); accountAgeWitnessService.onAllServicesInitialized();
} }
@Override
public void onSetupFailed(Throwable throwable) {
// Do nothing
}
@Override
public void onRequestCustomBridges() {
// Do nothing
}
});
}
private void setupConnectionLossCheck() {
// For dev testing (usually on BTC_REGTEST) we don't want to get the seed shut
// down as it is normal that the seed is the only actively running node.
if (Config.baseCurrencyNetwork() == BaseCurrencyNetwork.BTC_REGTEST) {
return;
}
if (checkConnectionLossTime != null) {
return;
}
checkConnectionLossTime = UserThread.runPeriodically(() -> {
if (injector.getInstance(PeerManager.class).getNumAllConnectionsLostEvents() > 1) {
// We set a flag to clear tor cache files at re-start. We cannot clear it now as Tor is used and
// that can cause problems.
injector.getInstance(User.class).getCookie().putAsBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART, true);
shutDown(this);
}
}, CHECK_CONNECTION_LOSS_SEC);
}
@Override
public void gracefulShutDown(ResultHandler resultHandler) {
super.gracefulShutDown(resultHandler);
}
} }

View File

@ -17,33 +17,23 @@
package bisq.seednode; package bisq.seednode;
import bisq.core.app.TorSetup;
import bisq.core.app.misc.ExecutableForAppWithP2p; import bisq.core.app.misc.ExecutableForAppWithP2p;
import bisq.core.dao.monitoring.DaoStateMonitoringService;
import bisq.core.dao.state.DaoStateSnapshotService; import bisq.core.dao.state.DaoStateSnapshotService;
import bisq.core.user.Cookie;
import bisq.core.user.CookieKey; import bisq.core.user.CookieKey;
import bisq.core.user.User; import bisq.core.user.User;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
import bisq.network.p2p.P2PServiceListener;
import bisq.network.p2p.peers.PeerManager;
import bisq.network.p2p.seed.SeedNodeRepository; import bisq.network.p2p.seed.SeedNodeRepository;
import bisq.common.Timer;
import bisq.common.UserThread; import bisq.common.UserThread;
import bisq.common.app.Capabilities; import bisq.common.app.Capabilities;
import bisq.common.app.Capability; import bisq.common.app.Capability;
import bisq.common.app.DevEnv; import bisq.common.app.DevEnv;
import bisq.common.app.Version; import bisq.common.app.Version;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.config.Config; import bisq.common.config.Config;
import bisq.common.handlers.ResultHandler; import bisq.common.handlers.ResultHandler;
import com.google.inject.Key;
import com.google.inject.name.Names;
import java.time.Instant; import java.time.Instant;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@ -57,14 +47,12 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class SeedNodeMain extends ExecutableForAppWithP2p { public class SeedNodeMain extends ExecutableForAppWithP2p {
private static final long CHECK_CONNECTION_LOSS_SEC = 30;
public static void main(String[] args) { public static void main(String[] args) {
new SeedNodeMain().execute(args); new SeedNodeMain().execute(args);
} }
private SeedNode seedNode; private SeedNode seedNode;
private Timer checkConnectionLossTimer; private DaoStateSnapshotService daoStateSnapshotService;
public SeedNodeMain() { public SeedNodeMain() {
super("Bisq Seednode", "bisq-seednode", "bisq_seednode", Version.VERSION); super("Bisq Seednode", "bisq-seednode", "bisq_seednode", Version.VERSION);
@ -84,19 +72,6 @@ public class SeedNodeMain extends ExecutableForAppWithP2p {
} }
///////////////////////////////////////////////////////////////////////////////////////////
// UncaughtExceptionHandler implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void handleUncaughtException(Throwable throwable, boolean doShutDown) {
if (throwable instanceof OutOfMemoryError || doShutDown) {
log.error("We got an OutOfMemoryError and shut down");
gracefulShutDown(() -> log.info("gracefulShutDown complete"));
}
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// We continue with a series of synchronous execution tasks // We continue with a series of synchronous execution tasks
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -105,14 +80,12 @@ public class SeedNodeMain extends ExecutableForAppWithP2p {
protected void applyInjector() { protected void applyInjector() {
super.applyInjector(); super.applyInjector();
daoStateSnapshotService = injector.getInstance(DaoStateSnapshotService.class);
seedNode = new SeedNode(injector); seedNode = new SeedNode(injector);
} }
@Override @Override
protected void startApplication() { protected void startApplication() {
super.startApplication();
Cookie cookie = injector.getInstance(User.class).getCookie();
if (cookie.getAsOptionalBoolean(CookieKey.DELAY_STARTUP).orElse(false)) { if (cookie.getAsOptionalBoolean(CookieKey.DELAY_STARTUP).orElse(false)) {
cookie.remove(CookieKey.DELAY_STARTUP); cookie.remove(CookieKey.DELAY_STARTUP);
try { try {
@ -125,24 +98,10 @@ public class SeedNodeMain extends ExecutableForAppWithP2p {
} }
} }
cookie.getAsOptionalBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART).ifPresent(cleanTorDirAtRestart -> { super.startApplication();
if (cleanTorDirAtRestart) {
injector.getInstance(TorSetup.class).cleanupTorFiles(() ->
cookie.remove(CookieKey.CLEAN_TOR_DIR_AT_RESTART),
log::error);
}
});
seedNode.startApplication(); seedNode.startApplication();
injector.getInstance(DaoStateMonitoringService.class).addListener(new DaoStateMonitoringService.Listener() { daoStateSnapshotService.setResyncDaoStateFromResourcesHandler(
@Override
public void onCheckpointFailed() {
gracefulShutDown();
}
});
injector.getInstance(DaoStateSnapshotService.class).setResyncDaoStateFromResourcesHandler(
// We set DELAY_STARTUP and shut down. At start up we delay with a deterministic delay to avoid // We set DELAY_STARTUP and shut down. At start up we delay with a deterministic delay to avoid
// that all seeds get restarted at the same time. // that all seeds get restarted at the same time.
() -> { () -> {
@ -150,61 +109,12 @@ public class SeedNodeMain extends ExecutableForAppWithP2p {
shutDown(this); shutDown(this);
} }
); );
injector.getInstance(P2PService.class).addP2PServiceListener(new P2PServiceListener() {
@Override
public void onDataReceived() {
// Do nothing
}
@Override
public void onNoSeedNodeAvailable() {
// Do nothing
}
@Override
public void onNoPeersAvailable() {
// Do nothing
}
@Override
public void onUpdatedDataReceived() {
// Do nothing
}
@Override
public void onTorNodeReady() {
// Do nothing
}
@Override
public void onHiddenServicePublished() {
boolean preventPeriodicShutdownAtSeedNode = injector.getInstance(Key.get(boolean.class,
Names.named(Config.PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE)));
if (!preventPeriodicShutdownAtSeedNode) {
startShutDownInterval();
}
UserThread.runAfter(() -> setupConnectionLossCheck(), 60);
}
@Override
public void onSetupFailed(Throwable throwable) {
// Do nothing
}
@Override
public void onRequestCustomBridges() {
// Do nothing
}
});
} }
@Override @Override
public void gracefulShutDown(ResultHandler resultHandler) { public void gracefulShutDown(ResultHandler resultHandler) {
seedNode.shutDown(); seedNode.shutDown();
if (checkConnectionLossTimer != null) {
checkConnectionLossTimer.stop();
}
super.gracefulShutDown(resultHandler); super.gracefulShutDown(resultHandler);
} }
@ -255,25 +165,4 @@ public class SeedNodeMain extends ExecutableForAppWithP2p {
NodeAddress myAddress = injector.getInstance(P2PService.class).getAddress(); NodeAddress myAddress = injector.getInstance(P2PService.class).getAddress();
return seedNodeAddresses.indexOf(myAddress); return seedNodeAddresses.indexOf(myAddress);
} }
private void setupConnectionLossCheck() {
// For dev testing (usually on BTC_REGTEST) we don't want to get the seed shut
// down as it is normal that the seed is the only actively running node.
if (Config.baseCurrencyNetwork() == BaseCurrencyNetwork.BTC_REGTEST) {
return;
}
if (checkConnectionLossTimer != null) {
return;
}
checkConnectionLossTimer = UserThread.runPeriodically(() -> {
if (injector.getInstance(PeerManager.class).getNumAllConnectionsLostEvents() > 1) {
// We set a flag to clear tor cache files at re-start. We cannot clear it now as Tor is used and
// that can cause problems.
injector.getInstance(User.class).getCookie().putAsBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART, true);
shutDown(this);
}
}, CHECK_CONNECTION_LOSS_SEC);
}
} }

View File

@ -25,7 +25,6 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class StatisticsMain extends ExecutableForAppWithP2p { public class StatisticsMain extends ExecutableForAppWithP2p {
public static void main(String[] args) { public static void main(String[] args) {
new StatisticsMain().execute(args); new StatisticsMain().execute(args);
} }
@ -44,11 +43,6 @@ public class StatisticsMain extends ExecutableForAppWithP2p {
keepRunning(); keepRunning();
} }
///////////////////////////////////////////////////////////////////////////////////////////
// We continue with a series of synchronous execution tasks
///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
protected void applyInjector() { protected void applyInjector() {
super.applyInjector(); super.applyInjector();