Browse Source

Propagate JVM arguments through auto-update. Improve start-up error messages shown by GUI

pull/67/head
catbref 5 years ago
parent
commit
62ed4e322b
  1. 30
      src/main/java/org/qora/ApplyUpdate.java
  2. 18
      src/main/java/org/qora/controller/AutoUpdate.java
  3. 29
      src/main/java/org/qora/controller/Controller.java
  4. 8
      src/main/java/org/qora/gui/Gui.java
  5. 4
      src/main/java/org/qora/network/Network.java
  6. 14
      src/main/java/org/qora/repository/hsqldb/HSQLDBRepositoryFactory.java

30
src/main/java/org/qora/ApplyUpdate.java

@ -1,11 +1,13 @@
package org.qora;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -42,7 +44,10 @@ public class ApplyUpdate {
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1);
// 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...");
@ -54,7 +59,7 @@ public class ApplyUpdate {
replaceJar();
// Restart node
restartNode();
restartNode(args);
LOGGER.info("Exiting...");
}
@ -122,7 +127,7 @@ public class ApplyUpdate {
LOGGER.error("Failed to replace JAR - giving up");
}
private static void restartNode() {
private static void restartNode(String[] args) {
String javaHome = System.getProperty("java.home");
LOGGER.info(String.format("Java home: %s", javaHome));
@ -133,10 +138,23 @@ public class ApplyUpdate {
LOGGER.info(String.format("Windows EXE launcher: %s", exeLauncher));
List<String> javaCmd;
if (Files.exists(exeLauncher))
if (Files.exists(exeLauncher)) {
javaCmd = Arrays.asList(exeLauncher.toString());
else
javaCmd = Arrays.asList(javaBinary.toString(), "-jar", JAR_FILENAME);
} else {
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 {
LOGGER.info(String.format("Restarting node with: %s", String.join(" ", javaCmd)));

18
src/main/java/org/qora/controller/AutoUpdate.java

@ -4,12 +4,14 @@ import java.awt.TrayIcon.MessageType;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -224,7 +226,21 @@ public class AutoUpdate extends Thread {
LOGGER.debug(String.format("Java binary: %s", javaBinary));
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)));
SysTray.getInstance().showMessage("Auto Update", "Applying automatic update and restarting...", MessageType.INFO);

29
src/main/java/org/qora/controller/Controller.java

@ -121,6 +121,7 @@ public class Controller extends Thread {
private final String buildVersion;
private final long buildTimestamp; // seconds
private String settingsFilename;
private AtomicReference<BlockData> chainTip = new AtomicReference<>();
@ -229,6 +230,10 @@ public class Controller extends Thread {
return this.blockchainLock;
}
/* package */ String getSettingsFilename() {
return this.settingsFilename;
}
// Entry point
public static void main(String[] args) {
@ -259,8 +264,16 @@ public class Controller extends Thread {
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(getRepositoryUrl());
RepositoryManager.setRepositoryFactory(repositoryFactory);
} catch (DataException e) {
LOGGER.error("Unable to start repository", e);
System.exit(1);
// If exception has no cause then repository is in use by some other process.
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");
@ -276,7 +289,8 @@ public class Controller extends Thread {
}
} catch (DataException 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");
@ -288,7 +302,8 @@ public class Controller extends Thread {
network.start();
} catch (Exception 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() {
@ -318,7 +333,8 @@ public class Controller extends Thread {
apiService.start();
} catch (Exception 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()));
@ -327,7 +343,8 @@ public class Controller extends Thread {
uiService.start();
} catch (Exception 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

8
src/main/java/org/qora/gui/Gui.java

@ -90,4 +90,12 @@ public class Gui {
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);
}
}

4
src/main/java/org/qora/network/Network.java

@ -136,10 +136,10 @@ public class Network {
serverChannel.register(channelSelector, SelectionKey.OP_ACCEPT);
} catch (UnknownHostException e) {
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) {
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<>();

14
src/main/java/org/qora/repository/hsqldb/HSQLDBRepositoryFactory.java

@ -26,6 +26,13 @@ public class HSQLDBRepositoryFactory implements RepositoryFactory {
private String connectionUrl;
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 {
// one-time initialization goes in here
this.connectionUrl = connectionUrl;
@ -36,12 +43,15 @@ public class HSQLDBRepositoryFactory implements RepositoryFactory {
} catch (SQLException e) {
Throwable cause = e.getCause();
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;
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());
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?
HSQLDBRepository.attemptRecovery(connectionUrl);
}

Loading…
Cancel
Save