Skip to content
Snippets Groups Projects
Commit 3559af4b authored by William Enright's avatar William Enright
Browse files

Fixed updater to use ZMQ for update handling instead of class loading

Change-Id: Ib5191cb6f54a20959dab26deb3acd5e76286ed7d
parent 00d008e6
Branches
No related tags found
No related merge requests found
Showing
with 250 additions and 363 deletions
......@@ -12,16 +12,9 @@
<artifactId>jams-launcher</artifactId>
<dependencies>
<dependency>
<groupId>net.jami</groupId>
<artifactId>jams-common</artifactId>
<version>${revision}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.jami</groupId>
<artifactId>jams-server</artifactId>
<version>${revision}</version>
<scope>compile</scope>
<groupId>org.zeromq</groupId>
<artifactId>jeromq</artifactId>
<version>${zmq.version}</version>
</dependency>
</dependencies>
......
......@@ -20,17 +20,19 @@
* 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 launcher.loaders.ServerLoader;
import launcher.loaders.UpdaterLoader;
import launcher.zmq.MessageReceiver;
import lombok.Getter;
import lombok.Setter;
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 org.zeromq.SocketType;
import org.zeromq.ZMQ;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@Slf4j
......@@ -39,64 +41,113 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class AppStarter extends Thread {
private final AtomicBoolean doUpdate = new AtomicBoolean(false);
private Server server;
private AppUpdater appUpdater;
private static Integer port = 8080;
private static String serverCertificate = null;
private static String serverPrivateKey = null;
public static ZMQ.Context context = ZMQ.context(1);
private static ZMQ.Socket publisher;
private static ZMQ.Socket receiver;
private MessageReceiver messageReceiver;
private static String[] parentArgs;
private long jamsProcessId = -1L;
/**
* 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) {
//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();
private void setupZmqBridge(){
publisher = context.socket(SocketType.PUB);
publisher.bind("tcp://*:4572");
//Use this to updater.
receiver = context.socket(SocketType.REP);
receiver.bind("tcp://*:4573");
messageReceiver = new MessageReceiver(receiver, doUpdate);
messageReceiver.start();
}
switch (args.length) {
case 1:
port = (Integer.parseInt(args[0]));
break;
case 3:
port = (Integer.parseInt(args[0]));
serverCertificate = (args[1]);
serverPrivateKey = (args[2]);
break;
default:
log.error("An unknown error occurred when parsing command line arguments!");
break;
private void unpackUpdate(){
for (File f : Objects.requireNonNull(new File(System.getProperty("user.dir") + "/tmp/").listFiles())) {
if (f.getName().contains("jams-server")) {
if (!f.renameTo(new File(System.getProperty("user.dir") + "/" + f.getName()))) {
log.info("An error occurred while attempting to move the file!");
} else {
f.delete();
}
} else {
if (!f.renameTo(new File(System.getProperty("user.dir") + "/libs/" + f.getName()))) {
log.info("An error occurred while attempting to move the file!");
} else {
f.delete();
}
}
}
// delete tmp folder
new File(System.getProperty("user.dir") + "/tmp/").delete();
}
public AppStarter(String[] args) {
parentArgs = args;
try {
jamsProcessId = startAccountManagementServer(args);
setupZmqBridge();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
log.info("Shutting down...");
ProcessHandle.of(jamsProcessId).get().destroyForcibly();
}));
} catch (Exception e) {
log.warn("Could not create and bind publisher and/or receiver! Please contact software developer");
System.exit(-1);
}
}
public static void main(String[] args) {
AppStarter appStarter = new AppStarter(args);
appStarter.start();
}
//How this works - once the JAMSUpdater has notified back upstream 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, Integer.toString(port), serverCertificate, serverPrivateKey);
while (true) {
try {
synchronized (doUpdate){
doUpdate.wait();
}
if (doUpdate.get()) {
Server.tomcatLauncher.stopTomcat();
//This will trigger a force reload of the lib.
LibraryLoader.loadlibs(System.getProperty("user.dir"), AppStarter.class);
server = ServerLoader.loadServer(appUpdater, Integer.toString(port), serverCertificate, serverPrivateKey);
this.doUpdate.set(false);
// Stop current process
ProcessHandle.of(jamsProcessId).get().destroyForcibly();
// transfer newly downloaded files to the right folder.
doUpdate.set(false);
//Unpack the update.
unpackUpdate();
// Restart the main JAR and set the processId to it.
jamsProcessId = startAccountManagementServer(parentArgs);
log.info("Update complete. Now running newest version");
}
synchronized (doUpdate) {
doUpdate.wait();
}
catch (Exception e) {
} catch (Exception e) {
log.error("An error occurred. Either while attempting to verify if an update was available, or" +
"when attempting to reload a library: {}", e.getMessage());
}
}
}
public static long startAccountManagementServer(String[] parentArgs) throws IOException {
ProcessBuilder pb = null;
switch (parentArgs.length) {
case 1:
pb = new ProcessBuilder("java", "-jar", "jams-server.jar", parentArgs[0]);
break;
case 3:
pb = new ProcessBuilder("java", "-jar", "jams-server.jar",
parentArgs[0], parentArgs[1], parentArgs[2]);
break;
default:
break;
}
assert pb != null;
pb.directory(new File(System.getProperty("user.dir")));
pb.inheritIO();
Process p = pb.start();
return p.pid();
}
}
\ No newline at end of file
/*
* 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.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, String port, String serverCertificate, String serverPrivateKey) {
try {
Class<?> cls = LibraryLoader.classLoader.loadClass("net.jami.jams.server.Server");
log.info("Server found, starting......");
return (Server) cls.getConstructor(AppUpdater.class, String.class, String.class, String.class).newInstance
(appUpdater, port, serverCertificate, serverPrivateKey);
}
catch (Exception e){
log.error("Could not find and start the server with error {}",e.getCause().getClass());
return null;
}
}
}
/*
* 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.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(AtomicBoolean updateSignaler) {
try {
Class<?> cls = LibraryLoader.classLoader.loadClass("net.jami.jams.updater.JAMSUpdater");
log.info("Updater service started...");
return (AppUpdater) cls.getConstructor(AtomicBoolean.class).newInstance(updateSignaler);
}
catch (Exception e){
log.error("Could not load update module...");
return null;
}
}
}
package launcher.zmq;
import lombok.Getter;
import org.zeromq.ZMQ;
import java.util.concurrent.atomic.AtomicBoolean;
@Getter
public class MessageReceiver extends Thread {
private final ZMQ.Socket socket;
private final 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")) {
//Use wait-notify mechanism to avoid burning CPU cycles.
synchronized (atomicBoolean) {
atomicBoolean.set(true);
atomicBoolean.notify();
}
}
}
catch (Exception e){
System.out.println("Some exception occurred!");
}
}
}
}
......@@ -73,6 +73,27 @@
<version>${revision}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.zeromq</groupId>
<artifactId>jeromq</artifactId>
<version>0.5.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.12</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
</dependencies>
<build>
......
......@@ -33,7 +33,6 @@ import net.jami.jams.common.cryptoengineapi.CertificateAuthority;
import net.jami.jams.common.jami.NameServer;
import net.jami.jams.common.serialization.JsoniterRegistry;
import net.jami.jams.common.server.ServerSettings;
import net.jami.jams.common.updater.AppUpdater;
import net.jami.jams.common.utils.LibraryLoader;
import net.jami.jams.nameserver.LocalNameServer;
import net.jami.jams.nameserver.PublicNameServer;
......@@ -41,6 +40,8 @@ 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.update.JAMSUpdater;
import net.jami.jams.server.update.UpdateInterface;
import java.awt.*;
import java.io.File;
......@@ -63,15 +64,8 @@ public class Server {
public static NameServer nameServer;
public static TomcatLauncher tomcatLauncher = null;
public static LicenseService licenseService = new LicenseService();
public static AppUpdater appUpdater;
public Server(AppUpdater appUpdater, String port, String serverCertificate, String serverPrivateKey) {
ClassPool.getDefault().clearImportedPackages();
JsoniterRegistry.initCodecs();
Server.appUpdater = appUpdater;
String[] args = {port, serverCertificate, serverPrivateKey};
main(args);
}
public static final UpdateInterface updateInterface = new UpdateInterface();
public static JAMSUpdater appUpdater = new JAMSUpdater(new AtomicBoolean(false));
public static void main(String[] args) {
......@@ -90,8 +84,6 @@ public class Server {
break;
}
//Look for the config.json file locally.
//Pre-load the libraries we should pre-load.
LibraryLoader.loadlibs("libs", Server.class);
//Step 1: Create the data store.
......
......@@ -22,6 +22,8 @@
*/
package net.jami.jams.server.servlets.api.admin.update;
import com.jsoniter.JsonIterator;
import com.jsoniter.any.Any;
import com.jsoniter.output.JsonStream;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
......@@ -30,10 +32,13 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import net.jami.jams.ca.JamsCA;
import net.jami.jams.common.annotations.ScopedServletMethod;
import net.jami.jams.common.objects.contacts.Contact;
import net.jami.jams.common.objects.responses.SubscriptionStatusResponse;
import net.jami.jams.common.objects.user.AccessLevel;
import net.jami.jams.server.Server;
import net.jami.jams.server.licensing.LicenseService;
import java.io.FileWriter;
import java.io.IOException;
@WebServlet("/api/admin/subscription")
......@@ -55,8 +60,23 @@ public class SubscriptionServlet extends HttpServlet {
// on disk..
@Override
@ScopedServletMethod(securityGroups = {AccessLevel.ADMIN})
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getInputStream().readAllBytes();
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setHeader("Access-Control-Allow-Origin", JamsCA.serverDomain);
String license = new String(req.getInputStream().readAllBytes());
if(license != null || !license.isBlank()) {
// create .dat file to be used later
FileWriter fw = new FileWriter("license.dat");
fw.write(license);
fw.close();
LicenseService licenseService = new LicenseService();
licenseService.loadLicense();
if (Server.activated.get()) {
resp.setStatus(200);
return;
}
}
resp.setStatus(500);
}
}
......@@ -31,6 +31,7 @@ import jakarta.servlet.http.HttpServletResponse;
import net.jami.jams.common.annotations.ScopedServletMethod;
import net.jami.jams.common.objects.user.AccessLevel;
import net.jami.jams.common.updater.FullSystemStatusResponse;
import net.jami.jams.server.Server;
import java.io.IOException;
......@@ -54,8 +55,8 @@ public class UpdateServlet extends HttpServlet {
@Override
@ScopedServletMethod(securityGroups = {AccessLevel.ADMIN})
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
if(appUpdater.getUpdateAvailable()){
if(appUpdater.getUpdateAvailable())
appUpdater.doUpdate();
}
}
}
......@@ -20,7 +20,7 @@
* 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.updater;
package net.jami.jams.server.update;
import com.jsoniter.JsonIterator;
import com.jsoniter.any.Any;
......@@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
import net.jami.jams.common.updater.AppUpdater;
import net.jami.jams.common.updater.FileDescription;
import net.jami.jams.common.utils.VersioningUtils;
import net.jami.jams.server.Server;
import java.io.IOException;
import java.io.InputStream;
......@@ -99,12 +100,8 @@ public class JAMSUpdater implements AppUpdater {
//Some logic here about replacing the existing files.
boolean res = updateDownloader.downloadFiles(getRemoteVersions());
//Notify back up-stream to the launcher that we want the update to happen.
if(res) {
doUpdate.set(true);
synchronized (doUpdate) {
doUpdate.notify();
}
}
if(res)
Server.updateInterface.approveUpdate();
else
log.error("Could not perform update - the downloaded files may have been invalid!");
}
......
......@@ -20,7 +20,7 @@
* 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.updater;
package net.jami.jams.server.update;
import com.jsoniter.JsonIterator;
import com.jsoniter.any.Any;
......
......@@ -20,7 +20,7 @@
* 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.updater;
package net.jami.jams.server.update;
import com.jsoniter.JsonIterator;
import com.jsoniter.any.Any;
......
package net.jami.jams.server.update;
import lombok.Getter;
import lombok.Setter;
import org.zeromq.SocketType;
import org.zeromq.ZMQ;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
@Getter
@Setter
public class UpdateInterface extends Thread {
private AtomicBoolean updateAvailable = new AtomicBoolean(false);
private volatile String versions;
private ZMQ.Context context = ZMQ.context(1);
private ZMQ.Socket sender = context.socket(SocketType.REQ);
private ZMQ.Socket receiver = context.socket(SocketType.SUB);
public UpdateInterface() {
receiver.connect("tcp://localhost:4572");
sender.connect("tcp://localhost:4573");
receiver.subscribe("UPDATE");
this.start();
}
public void approveUpdate(){
sender.send("DO-UPDATE");
}
@Override
public void run() {
while(true){
try{
receiver.recv();
updateAvailable.set(true);
versions = receiver.recvStr();
}
catch (Exception e){
System.out.println(e.toString());
}
}
}
}
{
"UPDATE_URL": "https://updates.jami.net",
"UPDATE_INTERVAL": 20000
}
......@@ -44,8 +44,8 @@ var api_path_get_server_status = '/api/info';
var api_path_get_post_configuration_auth_service = '/api/configuration/authservice';
var api_path_get_post_configuration_global_settings = '/api/configuration/globalsettings';
var api_path_post_configuration_change_password = '/api/admin/user';
var api_path_post_configuration_register_license = '/api/subscription';
var api_path_get_subscription_status = '/api/admin/subscription';
var api_path_post_subscription_load = '/api/admin/subscription';
var api_path_get_directories = '/api/auth/directories';
var api_path_get_needs_update = '/api/admin/update';
var api_path_get_start_update = '/api/admin/update';
......@@ -99,8 +99,9 @@ function ajaxApiCall(api_path, request_type, data, credentials, callBackFunction
// pass data in the header
if (data) {
if (api_path == api_path_get_user_directory_search || api_path == api_path_get_auth_user_search || api_path == api_path_get_user_search ||
(api_path == api_path_post_create_user && request_type == 'POST') || api_path == api_path_post_update_user
|| api_path == api_path_get_auth_devices || api_path == api_path_post_configuration_change_password || api_path == api_path_get_admin_devices)
(api_path == api_path_post_create_user && request_type == 'POST') || api_path == api_path_post_update_user ||
api_path == api_path_get_auth_devices || api_path == api_path_post_configuration_change_password || api_path == api_path_get_admin_devices ||
api_path == api_path_post_subscription_load)
isSearch = true;
// search dataType
......
......@@ -175,69 +175,6 @@ function setADblocks(ad_list) {
});
}
/*======== HSQL =============*/
// display add HSQL template form
// $('#addAuthenticationHSQL').on('click', function () {
// $('#HSQL-form-submit').text('Create HSQL authentication service');
// $('#HSQLModalCenter').modal('show');
// $("#HSQL-form")[0].reset();
// });
//
// // submit create/edit AD authentication
// $(document).on("submit","#HSQL-form",function (e) {
// e.preventDefault();
// setHSQLparametersData($(this));
// });
//
// function setHSQLparametersData(form) {
// event.preventDefault();
// var checked = "";
//
// if ($('#publicNS')[0].checked)
// checked = "http://ns.jami.net";
// else
// checked = window.location.origin;
//
// var data = {
// "CN": checked
// };
// // edit post request
// if (data) {
// ajaxApiCall(api_path_get_post_configuration_auth_service,'POST', data, null, callbackAuthentication);
// }
// // create post request
// else {
// delete data['configId'];
// auth_type = "HSQL";
// auth_action = "CREATE";
// ajaxApiCall(api_path_get_post_configuration_auth_service,'POST', data, null, callbackAuthentication);
// }
// }
//
// // set HSQL configuration blocks
// function setHSQLblocks(hsql_list) {
// $.each(hsql_list, function (index, hsql) {
// // set the display values
// var hsql_template = $($('#hsqlTemplate').html());
// var $new_hsql = hsql_template.clone();
// var usePublicNS = '';
//
// if (hsql_list[0].cN == "http://ns.jami.net")
// usePublicNS = "Yes";
// else
// usePublicNS = "No";
//
// $new_hsql.find('.mr-2').html("HSQL Authentication");
// $new_hsql.find('.mr-3').html("Using public nameserver: " + usePublicNS);
// var edit_button = $new_hsql.find('.edit-auth').attr('data-id', "HSQL");
// var delete_button = $new_hsql.find('.delete-auth').attr('data-id', "HSQL");
// $(edit_button).on( 'click', editAuthorizationHSQL);
// $(delete_button).on( 'click', deleteAuthorization);
// $new_hsql.insertAfter('#authDataWrapper');
// });
// }
/*======== SERVER PARAMETERS =============*/
// submit edit serverParameters
......@@ -357,10 +294,7 @@ $("#form-register-license").submit(function (event) {
setTimeout(function() {
$('.loading').hide();
if (base64License != "") {
jsonData = {
"base64License": base64License
}
ajaxApiCall(api_path_post_configuration_register_license, 'POST', jsonData, null, registerLicenseHandler, null);
ajaxApiCall(api_path_post_subscription_load, 'POST', base64License, null, registerLicenseHandler, null);
}
else {
$('.configMessage').remove();
......
......@@ -19,7 +19,6 @@
<module>jami-dht</module>
<module>authentication-module</module>
<module>jami-nameserver</module>
<module>updater</module>
<module>jams-launcher</module>
</modules>
......@@ -58,6 +57,7 @@
<maven.resources.version>3.1.0</maven.resources.version>
<embedded.ldap.unit>0.8.1</embedded.ldap.unit>
<maven.exec.version>1.1.1</maven.exec.version>
<zmq.version>0.5.2</zmq.version>
</properties>
<dependencies>
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jams3-parent</artifactId>
<groupId>net.jami</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>updater</artifactId>
<dependencies>
<dependency>
<groupId>net.jami</groupId>
<artifactId>jams-common</artifactId>
<version>${revision}</version>
<scope>compile</scope>
</dependency>
<dependency>
<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>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven.shade.version}</version>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<outputFile>../jams/${project.artifactId}.jar</outputFile>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<!-- add Main-Class to manifest file -->
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>net.jami.jams.server.Server</Main-Class>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Class-Path>.</Class-Path>
</manifestEntries>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment