From 2fb444df86d56246a8b5cee515eb91490c8dee05 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 15 Sep 2018 11:29:01 +1200 Subject: More work on service implementation --- pom.xml | 5 +++ setup/package.sh | 59 ++-------------------------- setup/setup.sh | 9 ++++- setup/traccar.iss | 5 +-- src/org/traccar/Main.java | 76 ++++++++++++++++++++++--------------- src/org/traccar/ServerManager.java | 2 +- src/org/traccar/WindowsService.java | 33 ++++++++-------- 7 files changed, 79 insertions(+), 110 deletions(-) diff --git a/pom.xml b/pom.xml index 8c4f52573..38d3f8626 100644 --- a/pom.xml +++ b/pom.xml @@ -179,6 +179,11 @@ jna-platform 4.5.2 + + com.github.jnr + jnr-posix + 3.0.46 + diff --git a/setup/package.sh b/setup/package.sh index 2534a3457..ed897c201 100755 --- a/setup/package.sh +++ b/setup/package.sh @@ -23,18 +23,13 @@ check_requirement () { } check_requirement "ls ../../ext-6.2.0" "Missing ../../ext-6.2.0 (https://www.sencha.com/legal/GPL/)" -check_requirement "ls yajsw-*.zip" "Missing yajsw-*.zip (https://sourceforge.net/projects/yajsw/files/)" check_requirement "ls innosetup-*.exe" "Missing isetup-*.exe (http://www.jrsoftware.org/isdl.php)" check_requirement "which sencha" "Missing sencha cmd package (https://www.sencha.com/products/extjs/cmd-download/)" check_requirement "which wine" "Missing wine package" check_requirement "which innoextract" "Missing innoextract package" check_requirement "which makeself" "Missing makeself package" -check_requirement "which dos2unix" "Missing dos2unix package" prepare () { - unzip yajsw-*.zip - mv yajsw-*/ yajsw/ - ../traccar-web/tools/minify.sh innoextract innosetup-*.exe @@ -42,50 +37,11 @@ prepare () { } cleanup () { - rm -r yajsw/ - rm ../traccar-web/web/app.min.js rm -r app/ } -copy_wrapper () { - cp yajsw/$1/setenv* out/$1 - cp yajsw/$1/wrapper* out/$1 - cp yajsw/$1/install* out/$1 - cp yajsw/$1/start* out/$1 - cp yajsw/$1/stop* out/$1 - cp yajsw/$1/uninstall* out/$1 - - chmod +x out/$1/* - - cp yajsw/conf/wrapper.conf.default out/conf - - touch out/conf/wrapper.conf - echo "wrapper.java.command=java" >> out/conf/wrapper.conf - echo "wrapper.java.app.jar=tracker-server.jar" >> out/conf/wrapper.conf - echo "wrapper.app.parameter.1=./conf/traccar.xml" >> out/conf/wrapper.conf - echo "wrapper.java.additional.1=-Dfile.encoding=UTF-8" >> out/conf/wrapper.conf - echo "wrapper.logfile=logs/wrapper.log.YYYYMMDD" >> out/conf/wrapper.conf - echo "wrapper.logfile.rollmode=DATE" >> out/conf/wrapper.conf - echo "wrapper.ntservice.name=traccar" >> out/conf/wrapper.conf - echo "wrapper.ntservice.displayname=Traccar" >> out/conf/wrapper.conf - echo "wrapper.ntservice.description=Traccar" >> out/conf/wrapper.conf - echo "wrapper.daemon.run_level_dir=\${if (new File('/etc/rc0.d').exists()) return '/etc/rcX.d' else return '/etc/init.d/rcX.d'}" >> out/conf/wrapper.conf - - cp -r yajsw/lib/* out/lib - find out/lib -type f -name ReadMe.txt -exec rm -f {} \; - - cp yajsw/templates/* out/templates - - cp yajsw/wrapper*.jar out - - if which xattr &>/dev/null - then - xattr -dr com.apple.quarantine out - fi -} - copy_files () { cp ../target/tracker-server.jar out cp ../target/lib/* out/lib @@ -97,9 +53,8 @@ copy_files () { } package_windows () { - mkdir -p out/{bat,conf,data,lib,logs,web,schema,templates} + mkdir -p out/{conf,data,lib,logs,web,schema,templates} - copy_wrapper "bat" copy_files wine app/ISCC.exe traccar.iss @@ -112,20 +67,15 @@ package_windows () { } package_unix () { - mkdir -p out/{bin,conf,data,lib,logs,web,schema,templates} - - copy_wrapper "bin" - sed -i.bak "1s/.*/#\!\/usr\/bin\/env bash/" out/bin/stopDaemonNoPriv.sh - rm out/bin/stopDaemonNoPriv.sh.bak - find out -type f \( -name \*.sh -o -name \*.vm \) -print0 | xargs -0 dos2unix + mkdir -p out/{conf,data,lib,logs,web,schema,templates} copy_files cp java-test/test.jar out cp setup.sh out + cp other/traccar.service out makeself --notemp out traccar.run "traccar" ./setup.sh zip -j traccar-linux-$VERSION.zip traccar.run README.txt - cp traccar-linux-$VERSION.zip traccar-macos-$VERSION.zip rm traccar.run rm -r out @@ -137,8 +87,7 @@ package_universal () { copy_files cp README.txt out - cp other/traccar.sh out - + cd out zip -r ../traccar-other-$VERSION.zip * cd .. diff --git a/setup/setup.sh b/setup/setup.sh index 51a139dd1..b27fcbe1c 100755 --- a/setup/setup.sh +++ b/setup/setup.sh @@ -9,8 +9,13 @@ then rm -r ../out rm /opt/traccar/setup.sh chmod -R go+rX /opt/traccar - cd /opt/traccar/bin/ - /opt/traccar/bin/installDaemon.sh + + mv /opt/traccar/traccar.service /etc/systemd/system + chmod 664 /etc/systemd/system/traccar.service + + systemctl daemon-reload + systemctl enable traccar.service + systemctl start traccar.service else echo 'Java 7 or higher is required' fi diff --git a/setup/traccar.iss b/setup/traccar.iss index f60b811f7..7bb599af2 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -7,7 +7,6 @@ OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 [Dirs] -Name: "{app}\bat" Name: "{app}\conf" Name: "{app}\data" Name: "{app}\lib" @@ -20,10 +19,10 @@ Name: "{app}\templates" Source: "out\*"; DestDir: "{app}"; Flags: recursesubdirs [Run] -Filename: "{app}\bat\installService.bat"; Parameters: ">%TEMP%\installService.log 2>&1"; Flags: runhidden +Filename: "java.exe"; Parameters: "-jar {app}\tracker-server.jar --install {app}\conf\traccar.xml"; Flags: runhidden [UninstallRun] -Filename: "{app}\bat\uninstallService.bat"; Parameters: ">%TEMP%\uninstallService.log 2>&1"; Flags: runhidden +Filename: "java.exe"; Parameters: "-jar {app}\tracker-server.jar --uninstall"; Flags: runhidden [Code] function GetLocalMachine(): Integer; diff --git a/src/org/traccar/Main.java b/src/org/traccar/Main.java index 986731240..992bfd8de 100644 --- a/src/org/traccar/Main.java +++ b/src/org/traccar/Main.java @@ -71,11 +71,16 @@ public final class Main { throw new RuntimeException("Configuration file is not provided"); } - String configFile = args[args.length - 1]; + final String configFile = args[args.length - 1]; - if (args.length > 1) { - WindowsService windowsService = new WindowsService("traccar"); - switch (args[1]) { + if (args[0].startsWith("--")) { + WindowsService windowsService = new WindowsService("traccar") { + @Override + public void run() { + Main.run(configFile); + } + }; + switch (args[0]) { case "--install": windowsService.install("traccar", null, null, null, null, configFile); return; @@ -87,40 +92,49 @@ public final class Main { windowsService.init(); break; } + } else { + run(configFile); } + } - Context.init(configFile); - logSystemInfo(); - LOGGER.info("Version: " + Context.getAppVersion()); - LOGGER.info("Starting server..."); - - Context.getServerManager().start(); - if (Context.getWebServer() != null) { - Context.getWebServer().start(); - } + public static void run(String configFile) { + try { + Context.init(configFile); + logSystemInfo(); + LOGGER.info("Version: " + Context.getAppVersion()); + LOGGER.info("Starting server..."); + + Context.getServerManager().start(); + if (Context.getWebServer() != null) { + Context.getWebServer().start(); + } - new Timer().scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - try { - Context.getDataManager().clearHistory(); - } catch (SQLException error) { - LOGGER.warn(null, error); + new Timer().scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + Context.getDataManager().clearHistory(); + } catch (SQLException error) { + LOGGER.warn(null, error); + } } - } - }, 0, CLEAN_PERIOD); + }, 0, CLEAN_PERIOD); - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - LOGGER.info("Shutting down server..."); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + LOGGER.info("Shutting down server..."); - if (Context.getWebServer() != null) { - Context.getWebServer().stop(); + if (Context.getWebServer() != null) { + Context.getWebServer().stop(); + } + Context.getServerManager().stop(); } - Context.getServerManager().stop(); - } - }); + }); + } catch (Exception e) { + LOGGER.error(null, e); + throw new RuntimeException(e); + } } } diff --git a/src/org/traccar/ServerManager.java b/src/org/traccar/ServerManager.java index a67f71be2..17c572ae3 100644 --- a/src/org/traccar/ServerManager.java +++ b/src/org/traccar/ServerManager.java @@ -44,7 +44,7 @@ public class ServerManager { List names = new LinkedList<>(); String packageName = "org.traccar.protocol"; String packagePath = packageName.replace('.', '/'); - URL packageUrl = Thread.currentThread().getContextClassLoader().getResource(packagePath); + URL packageUrl = getClass().getClassLoader().getResource(packagePath); if (packageUrl.getProtocol().equals("jar")) { String jarFileName = URLDecoder.decode(packageUrl.getFile(), StandardCharsets.UTF_8.name()); diff --git a/src/org/traccar/WindowsService.java b/src/org/traccar/WindowsService.java index 398648b7b..dccb01559 100644 --- a/src/org/traccar/WindowsService.java +++ b/src/org/traccar/WindowsService.java @@ -27,17 +27,15 @@ import com.sun.jna.platform.win32.Winsvc.SERVICE_MAIN_FUNCTION; import com.sun.jna.platform.win32.Winsvc.SERVICE_STATUS; import com.sun.jna.platform.win32.Winsvc.SERVICE_STATUS_HANDLE; import com.sun.jna.platform.win32.Winsvc.SERVICE_TABLE_ENTRY; +import jnr.posix.POSIXFactory; + import java.io.File; import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -public class WindowsService { +public abstract class WindowsService { private static final Advapi32 ADVAPI_32 = Advapi32.INSTANCE; - private final Object waitObject = new Object(); - private String serviceName; private ServiceMain serviceMain; private ServiceControl serviceControl; @@ -53,10 +51,8 @@ public class WindowsService { String javaHome = System.getProperty("java.home"); String javaBinary = javaHome + "\\bin\\java.exe"; - URLClassLoader cl = (URLClassLoader) WindowsService.class.getClassLoader(); - URL jarPath = cl.getURLs()[0]; - File jar = new File(jarPath.toURI()); + File jar = new File(WindowsService.class.getProtectionDomain().getCodeSource().getLocation().toURI()); String command = javaBinary + " -jar \"" + jar.getAbsolutePath() + "\" --service \"" + config + "\""; boolean success = false; @@ -145,7 +141,13 @@ public class WindowsService { return (success); } - public void init() { + public void init() throws URISyntaxException { + String path = new File( + WindowsService.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); + + POSIXFactory.getPOSIX().chdir(path); + System.setProperty("user.dir", path); + serviceMain = new ServiceMain(); SERVICE_TABLE_ENTRY entry = new SERVICE_TABLE_ENTRY(); entry.lpServiceName = serviceName; @@ -169,6 +171,8 @@ public class WindowsService { ADVAPI_32.SetServiceStatus(serviceStatusHandle, serviceStatus); } + public abstract void run(); + private class ServiceMain implements SERVICE_MAIN_FUNCTION { public void callback(int dwArgc, Pointer lpszArgv) { @@ -178,12 +182,8 @@ public class WindowsService { reportStatus(Winsvc.SERVICE_START_PENDING, WinError.NO_ERROR, 3000); reportStatus(Winsvc.SERVICE_RUNNING, WinError.NO_ERROR, 0); - try { - synchronized (waitObject) { - waitObject.wait(); - } - } catch (InterruptedException ex) { - } + run(); + reportStatus(Winsvc.SERVICE_STOPPED, WinError.NO_ERROR, 0); // Avoid returning from ServiceMain, which will cause a crash @@ -202,9 +202,6 @@ public class WindowsService { case Winsvc.SERVICE_CONTROL_SHUTDOWN: reportStatus(Winsvc.SERVICE_STOP_PENDING, WinError.NO_ERROR, 5000); System.exit(0); - synchronized (waitObject) { - waitObject.notifyAll(); - } default: break; } -- cgit v1.2.3