diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/responses/SubscriptionStatusResponse.java b/jams-common/src/main/java/net/jami/jams/common/objects/responses/SubscriptionStatusResponse.java index 4e7a61794bac8e9f1344c6200500a6fe6b747c4b..be34d2b7aec6447c7211feebce80fc72d1d6dc47 100644 --- a/jams-common/src/main/java/net/jami/jams/common/objects/responses/SubscriptionStatusResponse.java +++ b/jams-common/src/main/java/net/jami/jams/common/objects/responses/SubscriptionStatusResponse.java @@ -15,6 +15,6 @@ public class SubscriptionStatusResponse { private LicenseInformation licenseInformation; private Boolean activated; - private HashMap<String, FileDescription> versions = checkVersion(); + private HashMap<String, FileDescription> versions = checkVersion(null); } diff --git a/jams-common/src/main/java/net/jami/jams/common/utils/VersioningUtils.java b/jams-common/src/main/java/net/jami/jams/common/utils/VersioningUtils.java index c580fb105de050b79c5e28cf6691cda8af7e38fd..8696a6d1131d33dc9348255dfda234b012b0aaba 100644 --- a/jams-common/src/main/java/net/jami/jams/common/utils/VersioningUtils.java +++ b/jams-common/src/main/java/net/jami/jams/common/utils/VersioningUtils.java @@ -29,11 +29,12 @@ public class VersioningUtils { } } - public static HashMap<String, FileDescription> checkVersion() { + public static HashMap<String, FileDescription> checkVersion(String baseLocation) { try { HashMap<String,FileDescription> res = new HashMap<>(); ArrayList<Path> files = new ArrayList<>(); - Files.walk(Paths.get(System.getProperty("user.dir"))).filter(Files::isRegularFile).forEach(files::add); + if(baseLocation == null) baseLocation = System.getProperty("user.dir"); + Files.walk(Paths.get(baseLocation)).filter(Files::isRegularFile).forEach(files::add); files.forEach( e ->{ if(e.toString().endsWith(".jar")){ try { diff --git a/jams-common/src/test/java/net/jami/jams/common/utils/PasswordGeneratorTest.java b/jams-common/src/test/java/net/jami/jams/common/utils/PasswordGeneratorTest.java index 0c2a1d29660d29245067fb8b9d01f78371749da9..f64b16e31fef1c53f285c4c3756e55e9916a86ab 100644 --- a/jams-common/src/test/java/net/jami/jams/common/utils/PasswordGeneratorTest.java +++ b/jams-common/src/test/java/net/jami/jams/common/utils/PasswordGeneratorTest.java @@ -2,8 +2,6 @@ package net.jami.jams.common.utils; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - class PasswordGeneratorTest { @Test diff --git a/jams-common/src/test/java/net/jami/jams/common/utils/VersioningUtilsTest.java b/jams-common/src/test/java/net/jami/jams/common/utils/VersioningUtilsTest.java index e84c85c10adea27541417f4829f4416033597209..0cafd76b7e285fdec3ed28e53b49f463e8697cf8 100644 --- a/jams-common/src/test/java/net/jami/jams/common/utils/VersioningUtilsTest.java +++ b/jams-common/src/test/java/net/jami/jams/common/utils/VersioningUtilsTest.java @@ -12,7 +12,7 @@ class VersioningUtilsTest { @Test @Disabled public void testFileScan(){ - HashMap<String, FileDescription> res = VersioningUtils.checkVersion(); + HashMap<String, FileDescription> res = VersioningUtils.checkVersion(null); Assertions.assertEquals(6,res.size(),"Incorrect number of versions detected!"); } diff --git a/jams-launcher/pom.xml b/jams-launcher/pom.xml index a1668970417e49ad1b9eba0c7c5b6188b1536af6..c1357c67bb62caa2bb0c2e008c703723157a39e6 100644 --- a/jams-launcher/pom.xml +++ b/jams-launcher/pom.xml @@ -12,24 +12,16 @@ <artifactId>jams-launcher</artifactId> <dependencies> <dependency> - <groupId>org.apache.maven</groupId> - <artifactId>maven-model</artifactId> - <version>${maven.model.version}</version> + <groupId>net.jami</groupId> + <artifactId>jams-common</artifactId> + <version>${revision}</version> + <scope>compile</scope> </dependency> <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpcore</artifactId> - <version>${apache.httpcore.version}</version> - </dependency> - <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient</artifactId> - <version>${apache.httpclient.version}</version> - </dependency> - <dependency> - <groupId>org.zeromq</groupId> - <artifactId>jeromq</artifactId> - <version>${jeromq.version}</version> + <groupId>net.jami</groupId> + <artifactId>jams-server</artifactId> + <version>${revision}</version> + <scope>compile</scope> </dependency> </dependencies> diff --git a/jams-launcher/src/main/java/launcher/AppStarter.java b/jams-launcher/src/main/java/launcher/AppStarter.java index 4199a97fbd19f85358ecf09ee2e9957ba7b6e59e..161d876f80b0d7df26a80da0a82d712bda43d2b5 100644 --- a/jams-launcher/src/main/java/launcher/AppStarter.java +++ b/jams-launcher/src/main/java/launcher/AppStarter.java @@ -22,190 +22,55 @@ */ package launcher; -import com.google.common.hash.HashCode; -import com.google.common.hash.Hashing; -import org.zeromq.ZMQ; +import launcher.loaders.ServerLoader; +import launcher.loaders.UpdaterLoader; +import lombok.extern.slf4j.Slf4j; +import net.jami.jams.common.updater.AppUpdater; +import net.jami.jams.common.utils.LibraryLoader; +import net.jami.jams.server.Server; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Timer; -import java.util.TimerTask; -import java.util.logging.Logger; +import java.util.concurrent.atomic.AtomicBoolean; +@Slf4j public class AppStarter extends Thread { - private static Process applicationProcess; - private static long jamsPID; - private static Timer timer; - private final static Logger logger = Logger.getLogger(AppStarter.class.getName()); - public static ZMQ.Context context = ZMQ.context(1); - - + private final AtomicBoolean doUpdate = new AtomicBoolean(false); + private Server server; + private AppUpdater appUpdater; /** * The launcher is essentially responsible of firing up the main application JAR. * The problematic here is whenever we will fire up a JAR (but then we need to be able to * kill and restart his PID, or whenever we fork via a main). */ public static void main(String[] args) { - timer = startProcessCheckTimer(5000, args); - - - try { - logger.info("md5 for all packages: "); - logger.info("Core: " + checksum(System.getProperty("user.dir") + "/" + "jams-server.jar")); - logger.info("AD Connector: " + checksum(System.getProperty("user.dir") + "/libs/" + "ad-connector.jar")); - logger.info("LDAP Connector: " + checksum(System.getProperty("user.dir") + "/libs/" + "ldap-connector.jar")); - } catch (IOException e) { - e.printStackTrace(); - } - - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - System.out.println("Shutting down..."); - if (applicationProcess != null) - applicationProcess.destroy(); - })); - startProcess(args); + //We also need to fork the updater, which is a bit trickier, basically we just need a signaling + //system between both systems. + AppStarter appStarter = new AppStarter(); + appStarter.start(); } - public static Timer startProcessCheckTimer(long delay, String[] parentArgs) { - TimerTask pollTask = new TimerTask() { - @Override - public void run() { - // check if jams process is alive. If it's not, create another jams process and record it's pid. - // Then keep monitoring. - - if (!isStillAlive(Long.toString(jamsPID))) { - - try { - logger.info("Process with pid: " + jamsPID + " found dead. Resurrecting..."); - ProcessBuilder pb = startAccountManagementServer(parentArgs); - - if (pb != null) { - pb.inheritIO(); - pb.directory(new File(System.getProperty("user.dir"))); - logger.fine("Directory: " + pb.directory().getAbsolutePath()); - applicationProcess = pb.start(); - } - - // keep pid to monitor in memory - if (applicationProcess.isAlive()) - jamsPID = applicationProcess.pid(); - - logger.info("New PID: " + jamsPID); - } catch (IOException e) { - logger.severe("Exception thrown when attempting to startup jams process again!"); - } + //How this works - once the JAMSUpdater has notified back upstread to do an update, we lockdown + //and run the good old routine + @Override + public void run() { + //TODO: Hack this a bit to get it to work better - passing arguments damnit. + LibraryLoader.loadlibs(System.getProperty("user.dir"),AppStarter.class); + appUpdater = UpdaterLoader.loadUpdater(doUpdate); + server = ServerLoader.loadServer(appUpdater); + while(true){ + try{ + synchronized (doUpdate){ + doUpdate.wait(); } - - } - }; - Timer timer = new Timer(); - timer.scheduleAtFixedRate(pollTask, delay, - 25000); - - return timer; - } - - private static boolean isStillAlive(String pidStr) { - String OS = System.getProperty("os.name").toLowerCase(); - String command; - if (OS.indexOf("win") >= 0) { - logger.info("Check if pid " + pidStr + " is alive..."); - command = "cmd /c tasklist /FI \"PID eq " + pidStr + "\""; - } else if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.contains("mac")) { - logger.info("Check if pid " + pidStr + " is alive..."); - command = "ps -p " + pidStr; - } else { - logger.warning("Unsupported OS, failing gracefully... "); - return false; - } - return isProcessIdRunning(pidStr, command); // call generic implementation - } - - private static boolean isProcessIdRunning(String pid, String command) { - try { - Runtime rt = Runtime.getRuntime(); - Process pr = rt.exec(command); - - InputStreamReader isReader = new InputStreamReader(pr.getInputStream()); - BufferedReader bReader = new BufferedReader(isReader); - String strLine; - while ((strLine= bReader.readLine()) != null) { - if (strLine.contains(pid)) { - return true; + if(doUpdate.get()){ + Server.tomcatLauncher.stopTomcat(); + server = new Server(appUpdater); + this.doUpdate.set(false); } } + catch (Exception e){ - return false; - } catch (Exception ex) { - logger.severe("Got exception using system command!"); - return false; - } - } - - private static void startProcess(String[] parentArgs) { - try { - ProcessBuilder pb = startAccountManagementServer(parentArgs); - - if (pb != null) { - pb.inheritIO(); - pb.directory(new File(System.getProperty("user.dir"))); - logger.info("Directory: " + pb.directory().getAbsolutePath()); - applicationProcess = pb.start(); } - - // keep pid to monitor in memory - if (applicationProcess.isAlive()) - jamsPID = applicationProcess.pid(); - - } - catch (NullPointerException | IOException e) { - logger.severe("An exception occurred! " + e.toString()); - } - UpdateThread updateThread = new UpdateThread(applicationProcess, parentArgs); - updateThread.start(); - } - - public static ProcessBuilder startAccountManagementServer(String[] parentArgs) { - ProcessBuilder pb; - - switch(parentArgs.length) { - case 1: - pb = new ProcessBuilder("java", "-jar", "jams-server.jar", - parentArgs[0]); - break; - case 2: - pb = new ProcessBuilder("java", "-jar", "jams-server.jar", - parentArgs[0], parentArgs[1]); - break; - case 3: - pb = new ProcessBuilder("java", "-jar", "jams-server.jar", - parentArgs[0], parentArgs[1], parentArgs[2]); - break; - default: - pb = new ProcessBuilder("java", "-jar", System.getProperty("user.dir") + File.separator + "jams-server.jar"); - break; } - - return pb; - } - - private static String checksum(String filepath) throws IOException { - - HashCode hash = com.google.common.io.Files - .hash(new File(filepath), Hashing.md5()); - - return hash.toString(); } - - - public static Timer getTimer() { return timer; } - - public static void setTimer(Timer timer) { AppStarter.timer = timer; } - - public static long getJamsPID() { return jamsPID; } - - public static void setJamsPID(long jamsPID) { AppStarter.jamsPID = jamsPID; } } diff --git a/jams-launcher/src/main/java/launcher/MessageReceiver.java b/jams-launcher/src/main/java/launcher/MessageReceiver.java deleted file mode 100644 index 26e390615748133e6b2271403ca04ba0d3fc752e..0000000000000000000000000000000000000000 --- a/jams-launcher/src/main/java/launcher/MessageReceiver.java +++ /dev/null @@ -1,53 +0,0 @@ -/* -* Copyright (C) 2020 by Savoir-faire Linux -* Authors: William Enright <william.enright@savoirfairelinux.com> -* Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com> -* Johnny Flores <johnny.flores@savoirfairelinux.com> -* Mohammed Raza <mohammed.raza@savoirfairelinux.com> -* Felix Sidokhine <felix.sidokhine@savoirfairelinux.com> -* -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 3 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ -package launcher; - -import lombok.extern.slf4j.Slf4j; -import org.zeromq.ZMQ; - -import java.util.concurrent.atomic.AtomicBoolean; - -@Slf4j -public class MessageReceiver extends Thread { - - private ZMQ.Socket socket; - private AtomicBoolean atomicBoolean; - - public MessageReceiver(ZMQ.Socket socket, AtomicBoolean atomicBoolean) { - this.socket = socket; - this.atomicBoolean = atomicBoolean; - } - - @Override - public void run() { - while(true){ - try{ - String message = socket.recvStr(); - if(message.equals("DO-UPDATE")) atomicBoolean.set(true); - } - catch (Exception e){ - log.error("Some exception occurred on the message receiving thread, details {}!",e.getMessage()); - } - } - } -} diff --git a/jams-launcher/src/main/java/launcher/UpdateThread.java b/jams-launcher/src/main/java/launcher/UpdateThread.java deleted file mode 100644 index 0cd2856504b399d6bf4dd14e4d1e925c87da9028..0000000000000000000000000000000000000000 --- a/jams-launcher/src/main/java/launcher/UpdateThread.java +++ /dev/null @@ -1,348 +0,0 @@ -/* -* Copyright (C) 2020 by Savoir-faire Linux -* Authors: William Enright <william.enright@savoirfairelinux.com> -* Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com> -* Johnny Flores <johnny.flores@savoirfairelinux.com> -* Mohammed Raza <mohammed.raza@savoirfairelinux.com> -* Felix Sidokhine <felix.sidokhine@savoirfairelinux.com> -* -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 3 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ -package launcher; - -import com.google.common.hash.HashCode; -import com.google.common.hash.Hashing; -import com.jsoniter.JsonIterator; -import com.jsoniter.any.Any; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.ssl.SSLContexts; -import org.codehaus.plexus.util.FileUtils; -import org.zeromq.SocketType; -import org.zeromq.ZMQ; - -import javax.net.ssl.SSLContext; -import java.io.*; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.KeyFactory; -import java.security.KeyStore; -import java.security.MessageDigest; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.jar.Manifest; - -@Getter -@Setter -@Slf4j -public class UpdateThread extends Thread { - - private static final String IFACE_TCP_RECEIVER = "tcp://localhost:4573"; - private static final String IFACE_TCP_PUBLISHER = "tcp://localhost:4572"; - private static final String SUBSCRIBER_TOPIC = "UPDATE"; - - private HashMap<String, String> localVersions = new HashMap<>(); - private HashMap<String, String> localExecs = new HashMap<>(); - private HashMap<String, String> remoteVersions = new HashMap<>(); - private HashMap<String, String> remoteExecs = new HashMap<>(); - private HashMap<String, String> remoteChecksums = new HashMap<>(); - - private String[] parentArgs; - private static volatile String CORE_PACKAGE_MAIN_CLASS_NAME; - private static volatile String UPDATE_SERVER_URL; - private static volatile Long UPDATE_INTERVAL; - private SSLContext sslContext = null; - private Process applicationProcess; - private ZMQ.Socket publisher = AppStarter.context.socket(SocketType.PUB); - private ZMQ.Socket receiver = AppStarter.context.socket(SocketType.REP); - private AtomicBoolean doUpdate = new AtomicBoolean(false); - private MessageReceiver messageReceiver; - - - - public UpdateThread() { - } - - public UpdateThread(Process applicationProcess, String[] parentArgs) { - try { - publisher.bind(IFACE_TCP_PUBLISHER); - receiver.bind(IFACE_TCP_RECEIVER); - messageReceiver = new MessageReceiver(receiver,doUpdate); - messageReceiver.start(); - } catch (Exception e) { - log.warn("Could not create and bind publisher and/or receiver! Please contact software developer"); - System.exit(-1); - } - log.info("Update thread created..."); - this.parentArgs = parentArgs; - this.applicationProcess = applicationProcess; - } - - // This reads a file on the server which contains some basic info - // about what new versions of WHAT are available. - private void getLatestVersion() { - try { - //Step 1: Download a file called versions.json - HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build(); - HttpResponse response = httpClient.execute(new HttpGet(UPDATE_SERVER_URL + "/versions.json")); - //Step 2: Load the file into the hashmaps - Any any = JsonIterator.deserialize(response.getEntity().getContent().readAllBytes()); - any.asMap().forEach((k, v) -> { - remoteVersions.put(k, v.get("version").toString()); - remoteExecs.put(k, v.get("filename").toString()); - remoteChecksums.put(k, v.get("md5").toString()); - }); - } catch (Exception e) { - log.warn("Could not establish connection to JAMS Update Center with error: " + e.toString()); - } - } - - //You only need to load the keystore once, never do it again, you - //can theoretically put it as timer if you don't want users to - //restart the app. - public boolean loadLicense() { - try { - //Because apparently we should display versions even though the user has no license, we have to - //do this in two steps: - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - InputStream input = AppStarter.class.getClassLoader().getResourceAsStream("oem/ca.crt"); - if (input == null) { - System.out.println("No CA Found... this is critical!"); - System.exit(-1); - } - Certificate ca = cf.generateCertificate(input); - KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - trustStore.load(null, null); - trustStore.setCertificateEntry("ca", ca); - //Inject the SSL Connection here for a first time. - sslContext = SSLContexts.custom().loadTrustMaterial(trustStore, null) - .build(); - //The below will either pass or fail.. - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null); - if(!Files.exists(Path.of(System.getProperty("user.dir") + File.separator + "license.dat"))){ - System.out.println("You do not have a valid license - ignoring the rest of this function."); - System.out.println("You will still be notified about updates!"); - return false; - } - //Assuming the file exists, we just read the file. - String b64License = new String(Files.readAllBytes(Path.of(System.getProperty("user.dir") + File.separator + "license.dat"))); - //Since this is base64, we need to decode it. - String strLicense = new String(Base64.getDecoder().decode(b64License)); - //Now we need to split it. This is actually easy. - int cutPoint = strLicense.indexOf("-----BEGIN PRIVATE KEY-----"); - - String publicKey = strLicense.substring(0, cutPoint); - String privateKey = strLicense.substring(cutPoint); - - privateKey = privateKey.replaceAll("\\n", "").replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", ""); - KeyFactory kf = KeyFactory.getInstance("RSA"); - PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)); - PrivateKey pvk = kf.generatePrivate(keysp); - - InputStream inputStream = new ByteArrayInputStream(publicKey.getBytes(Charset.forName("UTF-8"))); - Certificate c = cf.generateCertificate(inputStream); - Certificate[] chain = new Certificate[]{c}; - - String alias1 = ((X509Certificate) c).getSubjectX500Principal().getName(); - ks.setCertificateEntry(alias1, c); - ks.setKeyEntry("", pvk, "".toCharArray(), chain); - try { - ((X509Certificate) c).checkValidity(); - c.verify(ca.getPublicKey()); - } catch (Exception e) { - log.warn("Your license is no longer valid or has been tampered with - " + e.toString()); - return false; - } - sslContext = SSLContexts.custom().loadKeyMaterial(ks, "".toCharArray()).loadTrustMaterial(trustStore, null) - .build(); - } catch (Exception e) { - log.warn("Could not read license file with error " + e.toString()); - return false; - } - return true; - } - - public void downloadFiles(HashMap<String, String> files) { - //I know this contradicts my dogma, but this really would have been an overkill for this project, - //I just claim that everything which is not core gets dumped to the lib directory. - - // temp folder for safe download and integrity check - File tmpFolder = new File(System.getProperty("user.dir") + "/tmp/"); - tmpFolder.mkdirs(); - - files.forEach((k, v) -> { - try { - HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build(); - HttpResponse httpResponse = httpClient.execute(new HttpGet(UPDATE_SERVER_URL + "/updates/" + v)); - if (httpResponse.getStatusLine().getStatusCode() == 200) { - log.info(tmpFolder.getPath() + "/" + files.get(k)); - FileOutputStream fos = new FileOutputStream(tmpFolder.getPath() + "/" + files.get(k)); - if (k.equals(CORE_PACKAGE_MAIN_CLASS_NAME)) { - httpResponse.getEntity().writeTo(fos); - fos.close(); - - if (checksum(tmpFolder.getPath() + "/" + files.get(k)).equals(remoteChecksums.get(k))) { - log.info("Successfully downloaded the core package!"); - remoteChecksums.remove(CORE_PACKAGE_MAIN_CLASS_NAME); - } - - } else { - httpResponse.getEntity().writeTo(fos); - fos.close(); - - if (checksum(tmpFolder.getPath() + "/" + files.get(k)).equals(remoteChecksums.get(k))) { - log.info("Successfully downloaded a library package!"); - remoteChecksums.remove(remoteChecksums.get(k)); - } - } - - } else { - log.warn("The server declared an update but does not have the required files?!"); - } - } catch (Exception e1) { - log.warn("Could not download an update with error " + e1.toString()); - } - }); - } - - //If the user clicks start update then kill, download, start - public void checkUpdate(){ - //Step 1: download the JSON file description (this would also contain the signatures). - getLatestVersion(); - //Step 2: compare the versions - we assume no admin is stupid enough to regress versions. - detectCurrentVersions(System.getProperty("user.dir")); - localVersions.forEach((k, v) -> { - if (remoteVersions.containsKey(k) && remoteVersions.get(k).equals(v)) { - remoteVersions.remove(k); - remoteExecs.remove(k); - } - }); - //Step 3: If there are no valid remote versions available, send an empty JSON. - if (remoteVersions.size() == 0){ - publisher.sendMore("UPDATE"); - publisher.send("{}"); - return; - } - else { - //In the new paradigm, we notify the server via zmq. - publisher.sendMore("UPDATE"); - publisher.send(remoteVersions.toString()); - } - } - - public void doUpdate() throws IOException{ - //Nothing to do here if the size was 0. - if(remoteVersions.size() == 0) return; - downloadFiles(remoteExecs); - if (!remoteChecksums.containsKey(CORE_PACKAGE_MAIN_CLASS_NAME)) { - - // stop AppStarter timer - AppStarter.getTimer().cancel(); - - // Stop current process - this.applicationProcess.destroy(); - - if (this.applicationProcess.isAlive()) - this.applicationProcess.destroyForcibly(); - - System.out.println("Murdered process with pid: " + AppStarter.getJamsPID()); - // delete old files - remoteExecs.forEach((k, v) -> { - log.info(remoteExecs.get(k)); - - if (k.equals(CORE_PACKAGE_MAIN_CLASS_NAME)) { - File f = new File(System.getProperty("user.dir") + "/" + remoteExecs.get(k)); - f.delete(); - f = new File(System.getProperty("user.dir") + "/tmp/" + remoteExecs.get(k)); - if (!f.renameTo(new File(System.getProperty("user.dir") + "/" + remoteExecs.get(k)))) - log.warn("An error occurred while attempting to move the file!"); - else - f.delete(); - } else { - File f = new File(System.getProperty("user.dir") + "/libs/" + remoteExecs.get(k)); - f.delete(); - f = new File(System.getProperty("user.dir") + "/tmp/" + remoteExecs.get(k)); - if (!f.renameTo(new File(System.getProperty("user.dir") + "/libs/" + remoteExecs.get(k)))) - log.warn("An error occurred while attempting to move the file!"); - else - f.delete(); - } - }); - - // Finally, start main jar - - ProcessBuilder pb = AppStarter.startAccountManagementServer(parentArgs); - pb.inheritIO(); - pb.directory(new File(System.getProperty("user.dir"))); - this.applicationProcess = pb.start(); - AppStarter.setJamsPID(this.applicationProcess.pid()); - //Start process check timer again - AppStarter.setTimer(AppStarter.startProcessCheckTimer(20000, parentArgs)); - - System.out.println("New PID: " + AppStarter.getJamsPID()); - System.out.println("Update complete. Now running newest version"); - - } else - System.out.println("An error occurred during the core package update process, the application has not been restarted."); - - // delete tmp folder - try { - FileUtils.deleteDirectory(System.getProperty("user.dir") + "/tmp/"); - } catch (IOException e) { - log.warn("An error occurred while attempting to delete /tmp/ folder!"); - } - } - - @Override - public void run() { - Timer timer = new Timer(); - // check if license is valid, then attempt SSL handshake with update server. - try { - log.info("Update timer started"); - TimerTask pollTask = new TimerTask() { - @Override - public void run() { - try { - loadLicense(); - checkUpdate(); - if(doUpdate.get()) { - doUpdate(); - } - } catch (Exception e) { - System.out.println("Exception thrown when attempting to update! " + e.toString()); - } - } - }; - timer.scheduleAtFixedRate(pollTask, 15000, UPDATE_INTERVAL); - } catch (Exception e) { - log.warn("error! " + e.toString()); - } - } -} \ No newline at end of file diff --git a/jams-launcher/src/main/java/launcher/loaders/ServerLoader.java b/jams-launcher/src/main/java/launcher/loaders/ServerLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..83ea6221f19cc003a3f82715dd446e109861299f --- /dev/null +++ b/jams-launcher/src/main/java/launcher/loaders/ServerLoader.java @@ -0,0 +1,22 @@ +package launcher.loaders; + +import lombok.extern.slf4j.Slf4j; +import net.jami.jams.common.updater.AppUpdater; +import net.jami.jams.common.utils.LibraryLoader; +import net.jami.jams.server.Server; + +@Slf4j +public class ServerLoader { + + public static Server loadServer(AppUpdater appUpdater) { + try { + Class<?> cls = LibraryLoader.classLoader.loadClass("net.jami.jams.server.Server"); + log.info("Server found, starting......"); + return (Server) cls.getConstructor(AppUpdater.class).newInstance(appUpdater); + } + catch (Exception e){ + log.error("Could not find and start the server with error {}",e.getCause().getClass()); + return null; + } + } +} diff --git a/jams-server/src/main/java/net/jami/jams/server/startup/UpdaterLoader.java b/jams-launcher/src/main/java/launcher/loaders/UpdaterLoader.java similarity index 65% rename from jams-server/src/main/java/net/jami/jams/server/startup/UpdaterLoader.java rename to jams-launcher/src/main/java/launcher/loaders/UpdaterLoader.java index bf0b9cb6d57f8ce08a1e4c2132f1f17942533e69..65c3434f197114a81ee613ec6d54b6c946512b10 100644 --- a/jams-server/src/main/java/net/jami/jams/server/startup/UpdaterLoader.java +++ b/jams-launcher/src/main/java/launcher/loaders/UpdaterLoader.java @@ -1,17 +1,19 @@ -package net.jami.jams.server.startup; +package launcher.loaders; import lombok.extern.slf4j.Slf4j; import net.jami.jams.common.updater.AppUpdater; import net.jami.jams.common.utils.LibraryLoader; +import java.util.concurrent.atomic.AtomicBoolean; + @Slf4j public class UpdaterLoader { - public static AppUpdater loadUpdater() { + public static AppUpdater loadUpdater(AtomicBoolean updateSignaler) { try { Class<?> cls = LibraryLoader.classLoader.loadClass("net.jami.jams.updater.JAMSUpdater"); log.info("Updater service started..."); - return (AppUpdater) cls.getConstructor().newInstance(); + return (AppUpdater) cls.getConstructor(AtomicBoolean.class).newInstance(updateSignaler); } catch (Exception e){ log.error("Could not load update module..."); diff --git a/jams-launcher/src/main/java/module-info.java b/jams-launcher/src/main/java/module-info.java index 4107c6e4b8e17ab94baeed18e9bb227e30b946c3..5a0f4a5c8624ec5d0a61e1c1e8d96fa45cb88dec 100644 --- a/jams-launcher/src/main/java/module-info.java +++ b/jams-launcher/src/main/java/module-info.java @@ -22,18 +22,12 @@ */ module jams.launcher { + exports launcher; requires lombok; requires org.slf4j; - requires jsoniter; - requires javassist; - requires jdk.crypto.cryptoki; requires java.base; - requires java.sql; - requires jeromq; - requires guava; - requires org.apache.httpcomponents.httpcore; - requires org.apache.httpcomponents.httpclient; - requires plexus.utils; requires jams.common; + requires jams.server; + requires org.apache.xbean.classloader; } diff --git a/jams-server/src/main/java/module-info.java b/jams-server/src/main/java/module-info.java index c4376ed080dba742b6185fcf3463fbb66992ee06..8e637e19b224a37c587ad4278f49c18c2d4810ff 100644 --- a/jams-server/src/main/java/module-info.java +++ b/jams-server/src/main/java/module-info.java @@ -48,6 +48,8 @@ module jams.server { exports net.jami.jams.server.servlets.api.install to org.apache.tomcat.embed.core; exports net.jami.jams.server.servlets.api.jaminameserver to org.apache.tomcat.embed.core; exports net.jami.jams.server.servlets.x509 to org.apache.tomcat.embed.core; + exports net.jami.jams.server; + exports net.jami.jams.server.core; } diff --git a/jams-server/src/main/java/net/jami/jams/server/Server.java b/jams-server/src/main/java/net/jami/jams/server/Server.java index ec3a7f6e7d2e286bfd6f686513f8c249db2984a5..08de4107091f1302989ec43702294c3f4940a686 100644 --- a/jams-server/src/main/java/net/jami/jams/server/Server.java +++ b/jams-server/src/main/java/net/jami/jams/server/Server.java @@ -1,25 +1,25 @@ /* -* Copyright (C) 2020 by Savoir-faire Linux -* Authors: William Enright <william.enright@savoirfairelinux.com> -* Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com> -* Johnny Flores <johnny.flores@savoirfairelinux.com> -* Mohammed Raza <mohammed.raza@savoirfairelinux.com> -* Felix Sidokhine <felix.sidokhine@savoirfairelinux.com> -* -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 3 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ + * Copyright (C) 2020 by Savoir-faire Linux + * Authors: William Enright <william.enright@savoirfairelinux.com> + * Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com> + * Johnny Flores <johnny.flores@savoirfairelinux.com> + * Mohammed Raza <mohammed.raza@savoirfairelinux.com> + * Felix Sidokhine <felix.sidokhine@savoirfairelinux.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ package net.jami.jams.server; import com.jsoniter.JsonIterator; @@ -40,7 +40,6 @@ import net.jami.jams.server.core.TomcatLauncher; import net.jami.jams.server.licensing.LicenseService; import net.jami.jams.server.startup.AuthModuleLoader; import net.jami.jams.server.startup.CryptoEngineLoader; -import net.jami.jams.server.startup.UpdaterLoader; import java.io.File; import java.io.FileInputStream; @@ -48,74 +47,88 @@ import java.io.InputStream; import java.util.concurrent.atomic.AtomicBoolean; @Slf4j +//In order to make this "stoppable" to simply, I turned the server itself into a thread. +//The reasoning: the main two problems public class Server { - public final static AtomicBoolean isInstalled = new AtomicBoolean(false); - public final static AtomicBoolean activated = new AtomicBoolean(false); + public final static AtomicBoolean isInstalled = new AtomicBoolean(false); + public final static AtomicBoolean activated = new AtomicBoolean(false); static { JsoniterRegistry.initCodecs(); } - public static DataStore dataStore; + public static DataStore dataStore; //This one gets loaded via JAR, to make it more flexible. - public static CertificateAuthority certificateAuthority; - public static AuthenticationModule userAuthenticationModule; - public static AppUpdater appUpdater; - public static NameServer nameServer; - private static TomcatLauncher tomcatLauncher = null; - public static final LicenseService licenseService = new LicenseService(); + public static CertificateAuthority certificateAuthority; + public static AuthenticationModule userAuthenticationModule; + public static NameServer nameServer; + public static TomcatLauncher tomcatLauncher = null; + public static LicenseService licenseService = new LicenseService(); + public static AppUpdater appUpdater; + + public Server(AppUpdater appUpdater) { + main(new String[]{}); + Server.appUpdater = appUpdater; + } + public static void main(String[] args) { //Start tomcat. - switch (args.length){ - case 0: tomcatLauncher = new TomcatLauncher(8080); break; - case 1: tomcatLauncher = new TomcatLauncher(Integer.parseInt(args[0])); break; - case 3: tomcatLauncher = new TomcatLauncher(Integer.parseInt(args[0]),args[1],args[2]); - default: log.error("Incorrect number of start arguments provided!"); System.exit(-1); break; + switch (args.length) { + case 0: + tomcatLauncher = new TomcatLauncher(8080); + break; + case 1: + tomcatLauncher = new TomcatLauncher(Integer.parseInt(args[0])); + break; + case 3: + tomcatLauncher = new TomcatLauncher(Integer.parseInt(args[0]), args[1], args[2]); + default: + log.error("Incorrect number of start arguments provided!"); + System.exit(-1); + break; } //Look for the config.json file locally. //Pre-load the libraries we should pre-load. - LibraryLoader.loadlibs("libs",Server.class); + LibraryLoader.loadlibs("libs", Server.class); //Step 1: Create the data store. dataStore = new DataStore("jdbc:derby:jams;create=true"); isInstalled.set(new File(System.getProperty("user.dir") + File.separator + "config.json").exists()); log.info("Server is already installed: " + isInstalled.get()); ServerSettings serverSettings = null; - if(isInstalled.get()){ + if (isInstalled.get()) { try { InputStream path = new FileInputStream(new File(System.getProperty("user.dir") + File.separator + "config.json")); - serverSettings = JsonIterator.deserialize(path.readAllBytes(),ServerSettings.class); - certificateAuthority = CryptoEngineLoader.loadCertificateAuthority(serverSettings.getCaConfiguration(),dataStore); - userAuthenticationModule = AuthModuleLoader.loadAuthenticationModule(dataStore,certificateAuthority); - if(serverSettings.getLdapConfiguration() != null) + serverSettings = JsonIterator.deserialize(path.readAllBytes(), ServerSettings.class); + certificateAuthority = CryptoEngineLoader.loadCertificateAuthority(serverSettings.getCaConfiguration(), dataStore); + userAuthenticationModule = AuthModuleLoader.loadAuthenticationModule(dataStore, certificateAuthority); + if (serverSettings.getLdapConfiguration() != null) userAuthenticationModule.attachAuthSource(AuthenticationSourceType.LDAP, serverSettings.getLdapConfiguration() ); - if(serverSettings.getActiveDirectoryConfiguration() != null){ + if (serverSettings.getActiveDirectoryConfiguration() != null) { userAuthenticationModule.attachAuthSource(AuthenticationSourceType.AD, serverSettings.getActiveDirectoryConfiguration()); } - if(serverSettings.getLocalDirectoryConfiguration() != null){ + if (serverSettings.getLocalDirectoryConfiguration() != null) { LocalAuthSettings settings = JsonIterator.deserialize(serverSettings.getActiveDirectoryConfiguration(), LocalAuthSettings.class); - if(settings.getPublicNames()) nameServer = new PublicNameServer(settings.getPublicNameServer()); - else nameServer = new LocalNameServer(dataStore,userAuthenticationModule,serverSettings.getServerPublicURI()); - } - else nameServer = new LocalNameServer(dataStore,userAuthenticationModule,serverSettings.getServerPublicURI()); - appUpdater = UpdaterLoader.loadUpdater(); + if (settings.getPublicNames()) nameServer = new PublicNameServer(settings.getPublicNameServer()); + else + nameServer = new LocalNameServer(dataStore, userAuthenticationModule, serverSettings.getServerPublicURI()); + } else + nameServer = new LocalNameServer(dataStore, userAuthenticationModule, serverSettings.getServerPublicURI()); licenseService.loadLicense(); log.info("All services are UP and ready for use..."); - } - catch (Exception e){ + } catch (Exception e) { log.error("Could not load configuration file or initialize some components - this is critical"); } - } - else{ - certificateAuthority = CryptoEngineLoader.loadCertificateAuthority(null,dataStore); - userAuthenticationModule = AuthModuleLoader.loadAuthenticationModule(dataStore,certificateAuthority); + } else { + certificateAuthority = CryptoEngineLoader.loadCertificateAuthority(null, dataStore); + userAuthenticationModule = AuthModuleLoader.loadAuthenticationModule(dataStore, certificateAuthority); log.info("Started server with empty modules waiting for setup..."); } } diff --git a/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java b/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java index e8643f8d84c29ad66f86941a146531486eab5ec7..82e7a693b8558962221f07fa57a6473862310712 100644 --- a/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java +++ b/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java @@ -23,7 +23,6 @@ package net.jami.jams.server.core; import lombok.extern.slf4j.Slf4j; -import net.jami.jams.server.Server; import org.apache.catalina.WebResourceRoot; import org.apache.catalina.core.StandardContext; import org.apache.catalina.startup.Tomcat; @@ -34,8 +33,6 @@ import org.apache.catalina.webresources.StandardRoot; import java.awt.*; import java.io.File; import java.net.URI; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; //This class boots the tomcat server which provides the subsystem @@ -43,9 +40,10 @@ import java.nio.charset.StandardCharsets; @Slf4j public class TomcatLauncher { - private static final Tomcat tomcat = new Tomcat(); + private Tomcat tomcat = null; public TomcatLauncher(int port) { + tomcat = new Tomcat(); tomcat.getService().addConnector(TomcatConnectorFactory.getNoSSLConnector(port)); this.startServer(); } @@ -57,9 +55,8 @@ public class TomcatLauncher { } - public void startServer() { - String jarName = URLDecoder.decode(new File(Server.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getAbsolutePath(), StandardCharsets.UTF_8); + String jarName = System.getProperty("user.dir") + File.separator + "jams-server.jar"; log.info("JAR Resource File = " + jarName); StandardContext context = (StandardContext) tomcat.addWebapp("", new File(System.getProperty("user.dir")).getAbsolutePath()); //Hack to prevent useless verbose messages. @@ -93,7 +90,19 @@ public class TomcatLauncher { else log.info("There is no graphical interface on this system - please connect remotely!"); } catch (Exception e) { - log.error("Web-server has failed to start - this is critical!"); + log.error("Web-server has failed to start - this is critical, error {}",e.getMessage()); + } + } + + public void stopTomcat(){ + try { + synchronized (tomcat) { + tomcat.stop(); + tomcat.destroy(); + } + } + catch (Exception e){ + log.info("Failed to stop tomcat server with error {}",e.getMessage()); } } } diff --git a/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java b/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java index 78e2a170a6118bcc958bf28310e75b563e18c847..8a6c5ab952663a465847bd6fe4074eb7d99dcbbd 100644 --- a/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java +++ b/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java @@ -34,7 +34,6 @@ import net.jami.jams.nameserver.PublicNameServer; import net.jami.jams.server.Server; import net.jami.jams.server.servlets.api.install.CachedObjects; import net.jami.jams.server.startup.AuthModuleLoader; -import net.jami.jams.server.startup.UpdaterLoader; import java.io.File; import java.io.FileOutputStream; @@ -115,8 +114,6 @@ public class InstallationFinalizer { ks.store(fos, password); fos.close(); log.info("Successfully built keystore for for tomcat!"); - appUpdater = UpdaterLoader.loadUpdater(); - log.info("Started subscription and update service!"); Server.isInstalled.set(true); log.info("The installation has completed successfully, you can now use JAMS!"); } catch (Exception e) { diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/NeedsUpdateServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/NeedsUpdateServlet.java index a5a8424928d8bed7420d86b9aada0251c12e4cc3..bdf31aa6236c03d0c1b2aa49ba0e9c20dd87b159 100644 --- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/NeedsUpdateServlet.java +++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/NeedsUpdateServlet.java @@ -1,14 +1,11 @@ package net.jami.jams.server.servlets.api.update; -import com.jsoniter.output.JsonStream; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import net.jami.jams.ca.JamsCA; -import net.jami.jams.server.Server; - import java.io.IOException; diff --git a/pom.xml b/pom.xml index 3ff549e6ff02a6dcc83b3587303d1359802e7ded..719339396f097384eeb8151d55df3e3cab1f136e 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ <module>authentication-module</module> <module>jami-nameserver</module> <module>updater</module> + <module>jams-launcher</module> </modules> <properties> diff --git a/updater/pom.xml b/updater/pom.xml index 4abff6158fe28f10defb15021bf9dee775a72f0d..16d4df799a8bf1a33a773c98351e5e5aca56a16e 100644 --- a/updater/pom.xml +++ b/updater/pom.xml @@ -18,9 +18,20 @@ <scope>compile</scope> </dependency> <dependency> - <groupId>org.zeromq</groupId> - <artifactId>jeromq</artifactId> - <version>${jeromq.version}</version> + <groupId>net.jami</groupId> + <artifactId>jams-launcher</artifactId> + <version>${revision}</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + <version>${apache.httpcore.version}</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>${apache.httpclient.version}</version> </dependency> </dependencies> @@ -38,7 +49,7 @@ <goal>shade</goal> </goals> <configuration> - <outputFile>../jams/libs/${project.artifactId}.jar</outputFile> + <outputFile>../jams/${project.artifactId}.jar</outputFile> <filters> <filter> <artifact>*:*</artifact> diff --git a/updater/src/main/java/module-info.java b/updater/src/main/java/module-info.java index c5b0f6dbbf810d37705ab62e98261c66d316b2ed..da50f318236d8d2995cb839bd71c32c5acd4d155 100644 --- a/updater/src/main/java/module-info.java +++ b/updater/src/main/java/module-info.java @@ -2,5 +2,5 @@ module updater { requires jams.common; requires lombok; requires org.slf4j; - requires jeromq; + requires jams.launcher; } \ No newline at end of file diff --git a/updater/src/main/java/net/jami/jams/updater/JAMSUpdater.java b/updater/src/main/java/net/jami/jams/updater/JAMSUpdater.java index 33fd8591818a55492c5af1639dd9c5448b3bb27b..1e12610f4006a6313306c3680041a98aa6d9c291 100644 --- a/updater/src/main/java/net/jami/jams/updater/JAMSUpdater.java +++ b/updater/src/main/java/net/jami/jams/updater/JAMSUpdater.java @@ -1,33 +1,44 @@ package net.jami.jams.updater; +import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.jami.jams.common.updater.AppUpdater; -import org.zeromq.SocketType; -import org.zeromq.ZMQ; import java.util.concurrent.atomic.AtomicBoolean; @Slf4j +@Getter +@Setter public class JAMSUpdater extends Thread implements AppUpdater { - private static final String IFACE_TCP_SENDER = "tcp://localhost:4573"; - private static final String IFACE_TCP_SUBSCRIBER = "tcp://localhost:4572"; - private static final String SUBSCRIBER_TOPIC = "UPDATE"; - private final AtomicBoolean updateAvailable = new AtomicBoolean(false); - private final ZMQ.Context context = ZMQ.context(1); - private final ZMQ.Socket sender = context.socket(SocketType.REQ); - private final ZMQ.Socket receiver = context.socket(SocketType.SUB); + private final AtomicBoolean doUpdate; private final UpdateDownloader updateDownloader = new UpdateDownloader(); - public JAMSUpdater() { - receiver.connect(IFACE_TCP_SUBSCRIBER); - sender.connect(IFACE_TCP_SENDER); - receiver.subscribe(SUBSCRIBER_TOPIC); + public JAMSUpdater(AtomicBoolean doUpdate) { + this.doUpdate = doUpdate; this.start(); + //As a mock I left this here, please remove it when this is done. } + @Override + public void run() { + try { + synchronized (this){ + this.wait(20_000); + } + this.doUpdate.set(true); + synchronized (doUpdate) { + doUpdate.notify(); + } + } + catch (Exception e){ + log.error("An error has occurred! {}",e.getMessage()); + } + } + @Override public String getLocalVersions() { return null; @@ -42,17 +53,4 @@ public class JAMSUpdater extends Thread implements AppUpdater { public boolean downloadUpdates() { return updateDownloader.doUpdate(); } - - @Override - public void run() { - while(true){ - try{ - receiver.recv(); - updateAvailable.set(true); - } - catch (Exception e){ - log.error("An error has occured with details {}",e.getMessage()); - } - } - } } diff --git a/updater/src/main/java/net/jami/jams/updater/LocalVersionRepository.java b/updater/src/main/java/net/jami/jams/updater/LocalVersionRepository.java index d9db31521fe9f8a2997770abb1e2d70d6cfa154f..f5557bb4efe9275222da857a96c2e8c0c11e2ba6 100644 --- a/updater/src/main/java/net/jami/jams/updater/LocalVersionRepository.java +++ b/updater/src/main/java/net/jami/jams/updater/LocalVersionRepository.java @@ -2,6 +2,7 @@ package net.jami.jams.updater; import net.jami.jams.common.updater.FileDescription; import net.jami.jams.common.updater.FileRepository; +import net.jami.jams.common.utils.VersioningUtils; import java.util.HashMap; @@ -9,6 +10,6 @@ public class LocalVersionRepository implements FileRepository { @Override public HashMap<String, FileDescription> getFileVersions() { - return null; + return VersioningUtils.checkVersion(null); } } diff --git a/updater/src/main/java/net/jami/jams/updater/RemoteVersionRepository.java b/updater/src/main/java/net/jami/jams/updater/RemoteVersionRepository.java deleted file mode 100644 index e45bc8b059b41bbc64c539c7589126d1044aaa87..0000000000000000000000000000000000000000 --- a/updater/src/main/java/net/jami/jams/updater/RemoteVersionRepository.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.jami.jams.updater; - -public class RemoteVersionRepository { -} diff --git a/updater/src/main/java/net/jami/jams/updater/UpdateCheckTask.java b/updater/src/main/java/net/jami/jams/updater/UpdateCheckTask.java index d41fd0d60aeea9fb7bfe828e808f26c1f2e8264c..ac664a8a00e3bee39a746c722ca885bb84663698 100644 --- a/updater/src/main/java/net/jami/jams/updater/UpdateCheckTask.java +++ b/updater/src/main/java/net/jami/jams/updater/UpdateCheckTask.java @@ -2,41 +2,19 @@ package net.jami.jams.updater; import lombok.extern.slf4j.Slf4j; -import javax.net.ssl.HttpsURLConnection; -import java.net.URL; -import java.util.List; import java.util.TimerTask; -import static net.jami.jams.updater.UpdateDaemon.UPDATE_SERVER_URI; - @Slf4j public class UpdateCheckTask extends TimerTask { - private final List<String> files; - protected UpdateCheckTask(List<String> files) { - this.files = files; + protected UpdateCheckTask() { } @Override public void run() { try { - URL url = new URL(UPDATE_SERVER_URI); - HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); - con.setRequestMethod("GET"); - if (con.getResponseCode() == 200) { - StringBuilder responseData = new StringBuilder(); - int respSize = Integer.parseInt(con.getHeaderField("Content-Length")); - int currentSize = 0; - while (currentSize < respSize) { - responseData.append((char) con.getInputStream().read()); - currentSize++; - } - log.info("Response received from update server {} ",con.getResponseCode()); - //TODO: Populate the files which "need" to be downloaded. - } else { - log.info("An error has occurred while checking for an update: {} ", con.getResponseCode()); - } + } catch (Exception e){ log.error("Could not check for updates with error: {}",e.getMessage()); diff --git a/updater/src/main/java/net/jami/jams/updater/UpdateDaemon.java b/updater/src/main/java/net/jami/jams/updater/UpdateDaemon.java index 5eeb87147bf3f8a2a831abfc7e4ed4990be6e077..11a7225008fb16d4de167322e0939b32d3b2558b 100644 --- a/updater/src/main/java/net/jami/jams/updater/UpdateDaemon.java +++ b/updater/src/main/java/net/jami/jams/updater/UpdateDaemon.java @@ -3,8 +3,6 @@ package net.jami.jams.updater; import lombok.Getter; import lombok.Setter; -import java.util.ArrayList; -import java.util.List; import java.util.Timer; @Getter @@ -13,10 +11,9 @@ public class UpdateDaemon extends Timer { //TODO: This should come from the resources file. public static final String UPDATE_SERVER_URI = "https://jami.net"; - public static final List<String> updateFiles = new ArrayList<>(); public UpdateDaemon() { - this.schedule(new UpdateCheckTask(updateFiles),0,150_000); + this.schedule(new UpdateCheckTask(),0,150_000); } } diff --git a/updater/src/main/java/net/jami/jams/updater/UpdateDownloader.java b/updater/src/main/java/net/jami/jams/updater/UpdateDownloader.java index a66798c1d23ebb97aa0058add2f4f557f3b4c650..f8123accc3d4540b84c6b4477443fc1c3b0f4109 100644 --- a/updater/src/main/java/net/jami/jams/updater/UpdateDownloader.java +++ b/updater/src/main/java/net/jami/jams/updater/UpdateDownloader.java @@ -2,13 +2,9 @@ package net.jami.jams.updater; import lombok.extern.slf4j.Slf4j; -import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; -import java.net.URL; -import static net.jami.jams.updater.UpdateDaemon.UPDATE_SERVER_URI; -import static net.jami.jams.updater.UpdateDaemon.updateFiles; @Slf4j public class UpdateDownloader { @@ -28,26 +24,6 @@ public class UpdateDownloader { " will take place..."); return false; } - for(String file : UpdateDaemon.updateFiles) { - URL url = new URL(UPDATE_SERVER_URI); - HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); - con.setSSLSocketFactory(sslSocketFactory); - con.setRequestMethod("GET"); - if (con.getResponseCode() == 200) { - StringBuilder responseData = new StringBuilder(); - int respSize = Integer.parseInt(con.getHeaderField("Content-Length")); - int currentSize = 0; - while (currentSize < respSize) { - responseData.append((char) con.getInputStream().read()); - currentSize++; - } - updateFiles.remove(file); - log.info("Successfully downloaded file..."); - } else { - log.info("An error has occurred while trying to download a file: {} ", con.getResponseCode()); - return false; - } - } return true; } catch (Exception e){ @@ -60,6 +36,9 @@ public class UpdateDownloader { try { //We assume the keystore already exists, because it gets created upon upload. //Basically just load the JKS keystore here. + + + //TODO: Load keystore from file. //Initialize the SSL context & load the SFL trust store. SSLContext sslContext = SSLContext.getInstance("SSL"); diff --git a/updater/src/main/java/net/jami/jams/updater/UpdateVersionRepository.java b/updater/src/main/java/net/jami/jams/updater/UpdateVersionRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..7c5570c8d37e20bc1198c9a1cea342058cd87769 --- /dev/null +++ b/updater/src/main/java/net/jami/jams/updater/UpdateVersionRepository.java @@ -0,0 +1,16 @@ +package net.jami.jams.updater; + +import net.jami.jams.common.updater.FileDescription; +import net.jami.jams.common.updater.FileRepository; +import net.jami.jams.common.utils.VersioningUtils; + +import java.io.File; +import java.util.HashMap; + +public class UpdateVersionRepository implements FileRepository { + + @Override + public HashMap<String, FileDescription> getFileVersions() { + return VersioningUtils.checkVersion(System.getProperty("user.dir") + File.separator + "tmp"); + } +}