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");
+    }
+}