package org.rr.jeborker; import static org.rr.commons.utils.StringUtil.EMPTY; import java.awt.EventQueue; import java.awt.Frame; import java.awt.SplashScreen; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.io.InputStream; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import org.rr.commons.log.LoggerFactory; import org.rr.commons.utils.ListUtils; import org.rr.commons.utils.ReflectionUtils; import org.rr.commons.utils.StringUtil; import org.rr.commons.utils.compression.rar.RarUtils; import org.rr.jeborker.app.JeboorkerLogger; import org.rr.jeborker.gui.MainController; import it.sauronsoftware.junique.AlreadyLockedException; import it.sauronsoftware.junique.JUnique; import it.sauronsoftware.junique.MessageHandler; public class Jeboorker { public static final ExecutorService APPLICATION_THREAD_POOL = new ThreadPoolExecutor(0, 1024, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ApplicationThreadFactory()) {}; public static final String APP = "Jeboorker"; public static final String URL = "https://github.com/meerkatzenwildschein/jeboorker"; private static MainController mainController; /** * Launch the application. */ public static void main(String[] args) { //setup the logger LoggerFactory.addHandler(new JeboorkerLogger()); setupClasspath(); //Setup the location for the rar executables. if(ReflectionUtils.getOS() == ReflectionUtils.OS_WINDOWS) { RarUtils.setRarExecFolder(getAppFolder() + File.separator + "exec"); } else { RarUtils.setRarExecFolder("/usr/bin"); } boolean isRunning = handleAlreadyRunning(); if(!isRunning) { try { logSystemInfo(); mainController = MainController.getController(); } catch (Exception e) { LoggerFactory.log(Level.SEVERE, null, "Main failed", e); System.exit(-1); } } else { // Sends arguments to the already active instance. JUnique.sendMessage(Jeboorker.class.getName(), EMPTY); LoggerFactory.log(Level.INFO, Jeboorker.class, "Jeboorker " + getAppVersion() + " is already running."); } closeSplashScreen(); } private static boolean handleAlreadyRunning() { try { JUnique.acquireLock(Jeboorker.class.getName(), new MessageHandler() { public String handle(String message) { if (mainController != null) { EventQueue.invokeLater(new Runnable() { @Override public void run() { int state = mainController.getMainWindow().getExtendedState(); state &= ~Frame.ICONIFIED; mainController.getMainWindow().setExtendedState(state); mainController.getMainWindow().setFocusableWindowState(false); mainController.getMainWindow().toFront(); mainController.getMainWindow().setFocusableWindowState(true); } }); } return null; } }); return false; } catch (AlreadyLockedException e) { // Application already running. return true; } } public static void closeSplashScreen() { if(SplashScreen.getSplashScreen() != null) { SplashScreen.getSplashScreen().close(); } } public static String getAppVersion() { Properties properties = new Properties(); try { InputStream pomProperties = Jeboorker.class.getClass().getResourceAsStream("/META-INF/maven/org.rr/jeboorker-main/pom.properties"); if(pomProperties != null) { properties.load(pomProperties); return properties.getProperty("version"); } } catch (IOException e) { LoggerFactory.log(Level.SEVERE, Jeboorker.class, "Failed to load version."); } return "UNKNOWN"; // fallback version } /** * Dumps the application version and the vm start parameters to the log */ private static void logSystemInfo() { RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); List<String> args = bean.getInputArguments(); String argsString = ListUtils.join(args, " "); LoggerFactory.getLogger().info("Jeboorker " + getAppVersion() + " started with " + argsString); Properties props = System.getProperties(); Set<Object> keys = props.keySet(); for(Object key : keys) { Object value = props.get(key); LoggerFactory.getLogger().info(StringUtil.toString(key) + "=" + StringUtil.toString(value)); } } /** * Get the application folder. Jeboorker must be configured that the app folder * is the current directory. */ public static String getAppFolder() { return System.getProperties().getProperty("user.dir"); } private static void setupClasspath() { try { String libFolder = getAppFolder() + File.separator + "lib/"; addPathToSystemClassLoader(new File(libFolder)); ReflectionUtils.addLibraryPath(libFolder); } catch (Exception e) { LoggerFactory.log(Level.SEVERE, null, "Classpath failed", e); System.exit(-1); } } /** * Add a classpath to the default system classloader. * @param dir The directory with jars to be added (not recursively) * @throws Exception */ public static void addPathToSystemClassLoader(File dir) throws Exception { if(dir != null && dir.isDirectory()) { final Set<String> jarFileSet = new HashSet<>(); final File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.getName().endsWith(".jar"); } }); if(files != null) { final URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); final Class<URLClassLoader> urlClass = URLClassLoader.class; final Method method = urlClass.getDeclaredMethod("addURL", new Class[] { URL.class }); method.setAccessible(true); for (int i = 0; i < files.length; i++) { if(jarFileSet == null || !jarFileSet.contains(files[i].getName())) { URL u = files[i].toURI().toURL(); method.invoke(urlClassLoader, new Object[] { u }); jarFileSet.add(files[i].getName()); } } } } } private static class ApplicationThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; ApplicationThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(final Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) { t.setDaemon(false); } if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); } return t; } } }