forked from Qortal/qortal
Propagate JVM arguments through auto-update. Improve start-up error messages shown by GUI
This commit is contained in:
parent
339e757d34
commit
62ed4e322b
@ -1,11 +1,13 @@
|
|||||||
package org.qora;
|
package org.qora;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -42,7 +44,10 @@ public class ApplyUpdate {
|
|||||||
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1);
|
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1);
|
||||||
|
|
||||||
// Load/check settings, which potentially sets up blockchain config, etc.
|
// Load/check settings, which potentially sets up blockchain config, etc.
|
||||||
Settings.getInstance();
|
if (args.length > 0)
|
||||||
|
Settings.fileInstance(args[0]);
|
||||||
|
else
|
||||||
|
Settings.getInstance();
|
||||||
|
|
||||||
LOGGER.info("Applying update...");
|
LOGGER.info("Applying update...");
|
||||||
|
|
||||||
@ -54,7 +59,7 @@ public class ApplyUpdate {
|
|||||||
replaceJar();
|
replaceJar();
|
||||||
|
|
||||||
// Restart node
|
// Restart node
|
||||||
restartNode();
|
restartNode(args);
|
||||||
|
|
||||||
LOGGER.info("Exiting...");
|
LOGGER.info("Exiting...");
|
||||||
}
|
}
|
||||||
@ -122,7 +127,7 @@ public class ApplyUpdate {
|
|||||||
LOGGER.error("Failed to replace JAR - giving up");
|
LOGGER.error("Failed to replace JAR - giving up");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void restartNode() {
|
private static void restartNode(String[] args) {
|
||||||
String javaHome = System.getProperty("java.home");
|
String javaHome = System.getProperty("java.home");
|
||||||
LOGGER.info(String.format("Java home: %s", javaHome));
|
LOGGER.info(String.format("Java home: %s", javaHome));
|
||||||
|
|
||||||
@ -133,10 +138,23 @@ public class ApplyUpdate {
|
|||||||
LOGGER.info(String.format("Windows EXE launcher: %s", exeLauncher));
|
LOGGER.info(String.format("Windows EXE launcher: %s", exeLauncher));
|
||||||
|
|
||||||
List<String> javaCmd;
|
List<String> javaCmd;
|
||||||
if (Files.exists(exeLauncher))
|
if (Files.exists(exeLauncher)) {
|
||||||
javaCmd = Arrays.asList(exeLauncher.toString());
|
javaCmd = Arrays.asList(exeLauncher.toString());
|
||||||
else
|
} else {
|
||||||
javaCmd = Arrays.asList(javaBinary.toString(), "-jar", JAR_FILENAME);
|
javaCmd = new ArrayList<>();
|
||||||
|
// Java runtime binary itself
|
||||||
|
javaCmd.add(javaBinary.toString());
|
||||||
|
|
||||||
|
// JVM arguments
|
||||||
|
javaCmd.addAll(ManagementFactory.getRuntimeMXBean().getInputArguments());
|
||||||
|
|
||||||
|
// Call mainClass in JAR
|
||||||
|
javaCmd.addAll(Arrays.asList("-jar", JAR_FILENAME));
|
||||||
|
|
||||||
|
if (args.length > 0)
|
||||||
|
// Add settings filename
|
||||||
|
javaCmd.add(args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LOGGER.info(String.format("Restarting node with: %s", String.join(" ", javaCmd)));
|
LOGGER.info(String.format("Restarting node with: %s", String.join(" ", javaCmd)));
|
||||||
|
@ -4,12 +4,14 @@ import java.awt.TrayIcon.MessageType;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -224,7 +226,21 @@ public class AutoUpdate extends Thread {
|
|||||||
LOGGER.debug(String.format("Java binary: %s", javaBinary));
|
LOGGER.debug(String.format("Java binary: %s", javaBinary));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<String> javaCmd = Arrays.asList(javaBinary.toString(), "-cp", NEW_JAR_FILENAME, ApplyUpdate.class.getCanonicalName());
|
List<String> javaCmd = new ArrayList<>();
|
||||||
|
// Java runtime binary itself
|
||||||
|
javaCmd.add(javaBinary.toString());
|
||||||
|
|
||||||
|
// JVM arguments
|
||||||
|
javaCmd.addAll(ManagementFactory.getRuntimeMXBean().getInputArguments());
|
||||||
|
|
||||||
|
// Call ApplyUpdate using new JAR
|
||||||
|
javaCmd.addAll(Arrays.asList("-cp", NEW_JAR_FILENAME, ApplyUpdate.class.getCanonicalName()));
|
||||||
|
|
||||||
|
// Are we running with different settings?
|
||||||
|
String settingsFilename = Controller.getInstance().getSettingsFilename();
|
||||||
|
if (settingsFilename != null)
|
||||||
|
javaCmd.add(settingsFilename);
|
||||||
|
|
||||||
LOGGER.info(String.format("Applying update with: %s", String.join(" ", javaCmd)));
|
LOGGER.info(String.format("Applying update with: %s", String.join(" ", javaCmd)));
|
||||||
|
|
||||||
SysTray.getInstance().showMessage("Auto Update", "Applying automatic update and restarting...", MessageType.INFO);
|
SysTray.getInstance().showMessage("Auto Update", "Applying automatic update and restarting...", MessageType.INFO);
|
||||||
|
@ -121,6 +121,7 @@ public class Controller extends Thread {
|
|||||||
|
|
||||||
private final String buildVersion;
|
private final String buildVersion;
|
||||||
private final long buildTimestamp; // seconds
|
private final long buildTimestamp; // seconds
|
||||||
|
private String settingsFilename;
|
||||||
|
|
||||||
private AtomicReference<BlockData> chainTip = new AtomicReference<>();
|
private AtomicReference<BlockData> chainTip = new AtomicReference<>();
|
||||||
|
|
||||||
@ -229,6 +230,10 @@ public class Controller extends Thread {
|
|||||||
return this.blockchainLock;
|
return this.blockchainLock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* package */ String getSettingsFilename() {
|
||||||
|
return this.settingsFilename;
|
||||||
|
}
|
||||||
|
|
||||||
// Entry point
|
// Entry point
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@ -259,8 +264,16 @@ public class Controller extends Thread {
|
|||||||
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(getRepositoryUrl());
|
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(getRepositoryUrl());
|
||||||
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
||||||
} catch (DataException e) {
|
} catch (DataException e) {
|
||||||
LOGGER.error("Unable to start repository", e);
|
// If exception has no cause then repository is in use by some other process.
|
||||||
System.exit(1);
|
if (e.getCause() == null) {
|
||||||
|
LOGGER.info("Repository in use by another process?");
|
||||||
|
Gui.getInstance().fatalError("Repository issue", "Repository in use by another process?");
|
||||||
|
} else {
|
||||||
|
LOGGER.error("Unable to start repository", e);
|
||||||
|
Gui.getInstance().fatalError("Repository issue", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return; // Not System.exit() so that GUI can display error
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.info("Validating blockchain");
|
LOGGER.info("Validating blockchain");
|
||||||
@ -276,7 +289,8 @@ public class Controller extends Thread {
|
|||||||
}
|
}
|
||||||
} catch (DataException e) {
|
} catch (DataException e) {
|
||||||
LOGGER.error("Couldn't validate blockchain", e);
|
LOGGER.error("Couldn't validate blockchain", e);
|
||||||
System.exit(2);
|
Gui.getInstance().fatalError("Blockchain validation issue", e);
|
||||||
|
return; // Not System.exit() so that GUI can display error
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.info("Starting controller");
|
LOGGER.info("Starting controller");
|
||||||
@ -288,7 +302,8 @@ public class Controller extends Thread {
|
|||||||
network.start();
|
network.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("Unable to start networking", e);
|
LOGGER.error("Unable to start networking", e);
|
||||||
System.exit(1);
|
Gui.getInstance().fatalError("Networking failure", e);
|
||||||
|
return; // Not System.exit() so that GUI can display error
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
@ -318,7 +333,8 @@ public class Controller extends Thread {
|
|||||||
apiService.start();
|
apiService.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("Unable to start API", e);
|
LOGGER.error("Unable to start API", e);
|
||||||
System.exit(1);
|
Gui.getInstance().fatalError("API failure", e);
|
||||||
|
return; // Not System.exit() so that GUI can display error
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.info(String.format("Starting node management UI on port %d", Settings.getInstance().getUiPort()));
|
LOGGER.info(String.format("Starting node management UI on port %d", Settings.getInstance().getUiPort()));
|
||||||
@ -327,7 +343,8 @@ public class Controller extends Thread {
|
|||||||
uiService.start();
|
uiService.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("Unable to start node management UI", e);
|
LOGGER.error("Unable to start node management UI", e);
|
||||||
System.exit(1);
|
Gui.getInstance().fatalError("Node management UI failure", e);
|
||||||
|
return; // Not System.exit() so that GUI can display error
|
||||||
}
|
}
|
||||||
|
|
||||||
// If GUI is enabled, we're no longer starting up but actually running now
|
// If GUI is enabled, we're no longer starting up but actually running now
|
||||||
|
@ -90,4 +90,12 @@ public class Gui {
|
|||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void fatalError(String title, Exception e) {
|
||||||
|
String message = e.getLocalizedMessage();
|
||||||
|
if (e.getCause() != null && e.getCause().getLocalizedMessage() != null)
|
||||||
|
message += ": " + e.getCause().getLocalizedMessage();
|
||||||
|
|
||||||
|
this.fatalError(title, message);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -136,10 +136,10 @@ public class Network {
|
|||||||
serverChannel.register(channelSelector, SelectionKey.OP_ACCEPT);
|
serverChannel.register(channelSelector, SelectionKey.OP_ACCEPT);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
LOGGER.error(String.format("Can't bind listen socket to address %s", Settings.getInstance().getBindAddress()));
|
LOGGER.error(String.format("Can't bind listen socket to address %s", Settings.getInstance().getBindAddress()));
|
||||||
throw new RuntimeException("Can't bind listen socket to address");
|
throw new RuntimeException("Can't bind listen socket to address", e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOGGER.error(String.format("Can't create listen socket: %s", e.getMessage()));
|
LOGGER.error(String.format("Can't create listen socket: %s", e.getMessage()));
|
||||||
throw new RuntimeException("Can't create listen socket");
|
throw new RuntimeException("Can't create listen socket", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedPeers = new ArrayList<>();
|
connectedPeers = new ArrayList<>();
|
||||||
|
@ -26,6 +26,13 @@ public class HSQLDBRepositoryFactory implements RepositoryFactory {
|
|||||||
private String connectionUrl;
|
private String connectionUrl;
|
||||||
private HSQLDBPool connectionPool;
|
private HSQLDBPool connectionPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs new RepositoryFactory using passed <tt>connectionUrl</tt>.
|
||||||
|
*
|
||||||
|
* @param connectionUrl
|
||||||
|
* @throws DataException <i>without throwable</i> if repository in use by another process.
|
||||||
|
* @throws DataException <i>with throwable</i> if repository cannot be opened for someother reason.
|
||||||
|
*/
|
||||||
public HSQLDBRepositoryFactory(String connectionUrl) throws DataException {
|
public HSQLDBRepositoryFactory(String connectionUrl) throws DataException {
|
||||||
// one-time initialization goes in here
|
// one-time initialization goes in here
|
||||||
this.connectionUrl = connectionUrl;
|
this.connectionUrl = connectionUrl;
|
||||||
@ -36,12 +43,15 @@ public class HSQLDBRepositoryFactory implements RepositoryFactory {
|
|||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
Throwable cause = e.getCause();
|
Throwable cause = e.getCause();
|
||||||
if (!(cause instanceof HsqlException))
|
if (!(cause instanceof HsqlException))
|
||||||
throw new DataException("Unable to open repository: " + e.getMessage());
|
throw new DataException("Unable to open repository: " + e.getMessage(), e);
|
||||||
|
|
||||||
HsqlException he = (HsqlException) cause;
|
HsqlException he = (HsqlException) cause;
|
||||||
if (he.getErrorCode() != -ErrorCode.ERROR_IN_LOG_FILE && he.getErrorCode() != -ErrorCode.M_DatabaseScriptReader_read)
|
if (he.getErrorCode() == -ErrorCode.LOCK_FILE_ACQUISITION_FAILURE)
|
||||||
throw new DataException("Unable to open repository: " + e.getMessage());
|
throw new DataException("Unable to open repository: " + e.getMessage());
|
||||||
|
|
||||||
|
if (he.getErrorCode() != -ErrorCode.ERROR_IN_LOG_FILE && he.getErrorCode() != -ErrorCode.M_DatabaseScriptReader_read)
|
||||||
|
throw new DataException("Unable to open repository: " + e.getMessage(), e);
|
||||||
|
|
||||||
// Attempt recovery?
|
// Attempt recovery?
|
||||||
HSQLDBRepository.attemptRecovery(connectionUrl);
|
HSQLDBRepository.attemptRecovery(connectionUrl);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user