mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 11:49:04 +01:00
Merge branch 'refs/heads/master' of ssh://akwizgran@briar.git.sourceforge.net/gitroot/briar/prototype
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
<classpathentry kind="lib" path="lib/platform.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jnotify-0.93.jar"/>
|
||||
<classpathentry kind="lib" path="lib/bluecove-gpl-2.1.0.jar" sourcepath="lib/source/bluecove-gpl-2.1.0-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/h2small-snapshot-2011-10-25.jar"/>
|
||||
<classpathentry kind="lib" path="lib/bluecove-2.1.0-briar.jar" sourcepath="lib/source/bluecove-2.1.0-briar-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/h2small-1.3.161.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
@@ -15,14 +15,18 @@ class ShutdownManagerImpl implements ShutdownManager {
|
||||
hooks = new HashMap<Integer, Thread>();
|
||||
}
|
||||
|
||||
public synchronized int addShutdownHook(Runnable runnable) {
|
||||
public synchronized int addShutdownHook(Runnable r) {
|
||||
int handle = nextHandle++;
|
||||
Thread hook = new Thread(runnable);
|
||||
Thread hook = createThread(r);
|
||||
hooks.put(handle, hook);
|
||||
Runtime.getRuntime().addShutdownHook(hook);
|
||||
return handle;
|
||||
}
|
||||
|
||||
protected Thread createThread(Runnable r) {
|
||||
return new Thread(r);
|
||||
}
|
||||
|
||||
public synchronized boolean removeShutdownHook(int handle) {
|
||||
Thread hook = hooks.remove(handle);
|
||||
if(hook == null) return false;
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
package net.sf.briar.lifecycle;
|
||||
|
||||
import java.awt.HeadlessException;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
|
||||
import net.sf.briar.util.OsUtils;
|
||||
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.platform.win32.WinDef.HINSTANCE;
|
||||
import com.sun.jna.platform.win32.WinDef.HMENU;
|
||||
import com.sun.jna.platform.win32.WinDef.HWND;
|
||||
import com.sun.jna.platform.win32.WinDef.LPARAM;
|
||||
import com.sun.jna.platform.win32.WinDef.LRESULT;
|
||||
import com.sun.jna.platform.win32.WinDef.WPARAM;
|
||||
import com.sun.jna.platform.win32.WinUser.MSG;
|
||||
import com.sun.jna.win32.StdCallLibrary;
|
||||
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;
|
||||
import com.sun.jna.win32.W32APIFunctionMapper;
|
||||
import com.sun.jna.win32.W32APITypeMapper;
|
||||
|
||||
class WindowsShutdownManagerImpl extends ShutdownManagerImpl {
|
||||
|
||||
@@ -23,36 +29,36 @@ class WindowsShutdownManagerImpl extends ShutdownManagerImpl {
|
||||
Logger.getLogger(WindowsShutdownManagerImpl.class.getName());
|
||||
|
||||
private static final int WM_QUERYENDSESSION = 17;
|
||||
private static final int WM_ENDSESSION = 22;
|
||||
private static final int GWL_WNDPROC = -4;
|
||||
private static final int WS_MINIMIZE = 0x20000000;
|
||||
|
||||
private final Map<String, Object> options;
|
||||
|
||||
private boolean initialised = false; // Locking: this
|
||||
|
||||
WindowsShutdownManagerImpl() {
|
||||
// Use the Unicode versions of Win32 API calls
|
||||
options = new TreeMap<String, Object>();
|
||||
options.put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
|
||||
options.put(Library.OPTION_FUNCTION_MAPPER,
|
||||
W32APIFunctionMapper.UNICODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int addShutdownHook(Runnable runnable) {
|
||||
public synchronized int addShutdownHook(Runnable r) {
|
||||
if(!initialised) initialise();
|
||||
return super.addShutdownHook(new RunOnce(runnable));
|
||||
return super.addShutdownHook(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Thread createThread(Runnable r) {
|
||||
return new StartOnce(r);
|
||||
}
|
||||
|
||||
// Locking: this
|
||||
private void initialise() {
|
||||
if(OsUtils.isWindows()) {
|
||||
try {
|
||||
HWND hwnd = new HWND();
|
||||
hwnd.setPointer(Native.getComponentPointer(new JFrame()));
|
||||
User32 u = (User32) Native.loadLibrary("user32", User32.class);
|
||||
try {
|
||||
// Load the 64-bit functions
|
||||
setCallback64Bit(u, hwnd);
|
||||
} catch(UnsatisfiedLinkError e) {
|
||||
// Load the 32-bit functions
|
||||
setCallback32Bit(u, hwnd);
|
||||
}
|
||||
} catch(HeadlessException e) {
|
||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||
} catch(UnsatisfiedLinkError e) {
|
||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||
}
|
||||
new EventLoop().start();
|
||||
} else {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning("Windows shutdown manager used on non-Windows OS");
|
||||
@@ -60,38 +66,6 @@ class WindowsShutdownManagerImpl extends ShutdownManagerImpl {
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
private void setCallback64Bit(final User32 user32, HWND hwnd) {
|
||||
final WindowProc oldProc = user32.GetWindowLongPtrW(hwnd, GWL_WNDPROC);
|
||||
WindowProc newProc = new WindowProc() {
|
||||
public LRESULT callback(HWND hwnd, int msg, WPARAM wp, LPARAM lp) {
|
||||
if(msg == WM_QUERYENDSESSION) {
|
||||
// It's safe to delay returning from this message
|
||||
runShutdownHooks();
|
||||
} else if(msg == WM_ENDSESSION) {
|
||||
// Return immediately or the JVM crashes on return
|
||||
}
|
||||
return user32.CallWindowProcPtrW(oldProc, hwnd, msg, wp, lp);
|
||||
}
|
||||
};
|
||||
user32.SetWindowLongPtrW(hwnd, GWL_WNDPROC, newProc);
|
||||
}
|
||||
|
||||
private void setCallback32Bit(final User32 user32, HWND hwnd) {
|
||||
final WindowProc oldProc = user32.GetWindowLongW(hwnd, GWL_WNDPROC);
|
||||
WindowProc newProc = new WindowProc() {
|
||||
public LRESULT callback(HWND hwnd, int msg, WPARAM wp, LPARAM lp) {
|
||||
if(msg == WM_QUERYENDSESSION) {
|
||||
// It's safe to delay returning from this message
|
||||
runShutdownHooks();
|
||||
} else if(msg == WM_ENDSESSION) {
|
||||
// Return immediately or the JVM crashes on return
|
||||
}
|
||||
return user32.CallWindowProcW(oldProc, hwnd, msg, wp, lp);
|
||||
}
|
||||
};
|
||||
user32.SetWindowLongW(hwnd, GWL_WNDPROC, newProc);
|
||||
}
|
||||
|
||||
// Package access for testing
|
||||
synchronized void runShutdownHooks() {
|
||||
// Start each hook in its own thread
|
||||
@@ -106,33 +80,81 @@ class WindowsShutdownManagerImpl extends ShutdownManagerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private static class RunOnce implements Runnable {
|
||||
private class EventLoop extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Load user32.dll
|
||||
final User32 user32 = (User32) Native.loadLibrary("user32",
|
||||
User32.class, options);
|
||||
// Create a callback to handle the WM_QUERYENDSESSION message
|
||||
WindowProc proc = new WindowProc() {
|
||||
public LRESULT callback(HWND hwnd, int msg, WPARAM wp,
|
||||
LPARAM lp) {
|
||||
if(msg == WM_QUERYENDSESSION) {
|
||||
// It's safe to delay returning from this message
|
||||
runShutdownHooks();
|
||||
}
|
||||
// Pass the message to the default window procedure
|
||||
return user32.DefWindowProc(hwnd, msg, wp, lp);
|
||||
}
|
||||
};
|
||||
// Create a native window
|
||||
HWND hwnd = user32.CreateWindowEx(0, "STATIC", "", WS_MINIMIZE,
|
||||
0, 0, 0, 0, null, null, null, null);
|
||||
// Register the callback
|
||||
try {
|
||||
// Use SetWindowLongPtr if available (64-bit safe)
|
||||
user32.SetWindowLongPtr(hwnd, GWL_WNDPROC, proc);
|
||||
if(LOG.isLoggable(Level.INFO))
|
||||
LOG.info("Registered 64-bit callback");
|
||||
} catch(UnsatisfiedLinkError e) {
|
||||
// Use SetWindowLong if SetWindowLongPtr isn't available
|
||||
user32.SetWindowLong(hwnd, GWL_WNDPROC, proc);
|
||||
if(LOG.isLoggable(Level.INFO))
|
||||
LOG.info("Registered 32-bit callback");
|
||||
}
|
||||
// Handle events until the window is destroyed
|
||||
MSG msg = new MSG();
|
||||
while(user32.GetMessage(msg, null, 0, 0) > 0) {
|
||||
user32.TranslateMessage(msg);
|
||||
user32.DispatchMessage(msg);
|
||||
}
|
||||
} catch(UnsatisfiedLinkError e) {
|
||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class StartOnce extends Thread {
|
||||
|
||||
private final Runnable runnable;
|
||||
private final AtomicBoolean called = new AtomicBoolean(false);
|
||||
|
||||
private RunOnce(Runnable runnable) {
|
||||
this.runnable = runnable;
|
||||
private StartOnce(Runnable r) {
|
||||
super(r);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if(called.getAndSet(true)) return;
|
||||
runnable.run();
|
||||
@Override
|
||||
public void start() {
|
||||
// Ensure the thread is only started once
|
||||
if(!called.getAndSet(true)) super.start();
|
||||
}
|
||||
}
|
||||
|
||||
private static interface User32 extends StdCallLibrary {
|
||||
|
||||
LRESULT CallWindowProcW(WindowProc oldProc, HWND hwnd, int msg,
|
||||
WPARAM wp, LPARAM lp);
|
||||
LRESULT CallWindowProcPtrW(WindowProc oldProc, HWND hwnd, int msg,
|
||||
WPARAM wp, LPARAM lp);
|
||||
HWND CreateWindowEx(int styleEx, String className, String windowName,
|
||||
int style, int x, int y, int width, int height, HWND parent,
|
||||
HMENU menu, HINSTANCE instance, Pointer param);
|
||||
|
||||
WindowProc GetWindowLongW(HWND hwnd, int index);
|
||||
WindowProc GetWindowLongPtrW(HWND hwnd, int index);
|
||||
LRESULT DefWindowProc(HWND hwnd, int msg, WPARAM wp, LPARAM lp);
|
||||
LRESULT SetWindowLong(HWND hwnd, int index, WindowProc newProc);
|
||||
LRESULT SetWindowLongPtr(HWND hwnd, int index, WindowProc newProc);
|
||||
|
||||
LRESULT SetWindowLongW(HWND hwnd, int index, WindowProc newProc);
|
||||
LRESULT SetWindowLongPtrW(HWND hwnd, int index, WindowProc newProc);
|
||||
int GetMessage(MSG msg, HWND hwnd, int filterMin, int filterMax);
|
||||
boolean TranslateMessage(MSG msg);
|
||||
LRESULT DispatchMessage(MSG msg);
|
||||
}
|
||||
|
||||
private static interface WindowProc extends StdCallCallback {
|
||||
|
||||
@@ -18,9 +18,14 @@ public class RemovableDrivePluginFactory implements BatchPluginFactory {
|
||||
if(OsUtils.isLinux()) {
|
||||
finder = new LinuxRemovableDriveFinder();
|
||||
monitor = new LinuxRemovableDriveMonitor();
|
||||
} else if(OsUtils.isMac()) {
|
||||
} else if(OsUtils.isMacLeopardOrNewer()) {
|
||||
finder = new MacRemovableDriveFinder();
|
||||
monitor = new MacRemovableDriveMonitor();
|
||||
} else if(OsUtils.isMac()) {
|
||||
// JNotify requires OS X 10.5 or newer, so we have to poll
|
||||
finder = new MacRemovableDriveFinder();
|
||||
monitor = new PollingRemovableDriveMonitor(finder,
|
||||
POLLING_INTERVAL);
|
||||
} else if(OsUtils.isWindows()) {
|
||||
finder = new WindowsRemovableDriveFinder();
|
||||
monitor = new PollingRemovableDriveMonitor(finder,
|
||||
|
||||
BIN
lib/h2small-1.3.161.jar
Normal file
BIN
lib/h2small-1.3.161.jar
Normal file
Binary file not shown.
Binary file not shown.
@@ -27,6 +27,7 @@
|
||||
<test name='net.sf.briar.i18n.I18nTest'/>
|
||||
<test name='net.sf.briar.invitation.InvitationWorkerTest'/>
|
||||
<test name='net.sf.briar.lifecycle.ShutdownManagerImplTest'/>
|
||||
<test name='net.sf.briar.lifecycle.WindowsShutdownManagerImplTest'/>
|
||||
<test name='net.sf.briar.plugins.PluginManagerImplTest'/>
|
||||
<test name='net.sf.briar.plugins.file.LinuxRemovableDriveFinderTest'/>
|
||||
<test name='net.sf.briar.plugins.file.MacRemovableDriveFinderTest'/>
|
||||
|
||||
@@ -12,7 +12,7 @@ public class ShutdownManagerImplTest extends TestCase {
|
||||
|
||||
@Test
|
||||
public void testAddAndRemove() {
|
||||
ShutdownManager s = new ShutdownManagerImpl();
|
||||
ShutdownManager s = createShutdownManager();
|
||||
Set<Integer> handles = new HashSet<Integer>();
|
||||
for(int i = 0; i < 100; i++) {
|
||||
int handle = s.addShutdownHook(new Runnable() {
|
||||
@@ -26,4 +26,8 @@ public class ShutdownManagerImplTest extends TestCase {
|
||||
// The hooks should no longer be removable
|
||||
for(int handle : handles) assertFalse(s.removeShutdownHook(handle));
|
||||
}
|
||||
|
||||
protected ShutdownManager createShutdownManager() {
|
||||
return new ShutdownManagerImpl();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package net.sf.briar.lifecycle;
|
||||
|
||||
import net.sf.briar.api.lifecycle.ShutdownManager;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class WindowsShutdownManagerImplTest extends ShutdownManagerImplTest {
|
||||
|
||||
@Override
|
||||
protected ShutdownManager createShutdownManager() {
|
||||
return new WindowsShutdownManagerImpl();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManagerWaitsForHooksToRun() {
|
||||
WindowsShutdownManagerImpl s = new WindowsShutdownManagerImpl();
|
||||
SlowHook[] hooks = new SlowHook[10];
|
||||
for(int i = 0; i < hooks.length; i++) {
|
||||
hooks[i] = new SlowHook();
|
||||
s.addShutdownHook(hooks[i]);
|
||||
}
|
||||
s.runShutdownHooks();
|
||||
for(int i = 0; i < hooks.length; i++) assertTrue(hooks[i].finished);
|
||||
}
|
||||
|
||||
private static class SlowHook implements Runnable {
|
||||
|
||||
private volatile boolean finished = false;
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
finished = true;
|
||||
} catch(InterruptedException e) {
|
||||
// Don't finish
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,9 +41,12 @@ public class PluginManagerImplTest extends TestCase {
|
||||
Poller poller = new PollerImpl();
|
||||
PluginManagerImpl p = new PluginManagerImpl(db, executor, poller,
|
||||
dispatcher, uiCallback);
|
||||
// The Bluetooth plugin will not start without a Bluetooth device, so
|
||||
// we expect two plugins to be started
|
||||
assertEquals(2, p.startPlugins());
|
||||
assertEquals(2, p.stopPlugins());
|
||||
// We expect either 2 or 3 plugins to be started, depending on whether
|
||||
// the test machine has a Bluetooth device
|
||||
int started = p.startPlugins();
|
||||
int stopped = p.stopPlugins();
|
||||
assertEquals(started, stopped);
|
||||
assertTrue(started >= 2);
|
||||
assertTrue(started <= 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.briar.TestUtils;
|
||||
import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback;
|
||||
import net.sf.briar.util.OsUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -25,6 +26,10 @@ public class UnixRemovableDriveMonitorTest extends TestCase {
|
||||
|
||||
@Test
|
||||
public void testNonexistentDir() throws Exception {
|
||||
if(!OsUtils.isLinux() || OsUtils.isMacLeopardOrNewer()) {
|
||||
System.err.println("Warning: Skipping test");
|
||||
return;
|
||||
}
|
||||
File doesNotExist = new File(testDir, "doesNotExist");
|
||||
RemovableDriveMonitor monitor = createMonitor(doesNotExist);
|
||||
monitor.start(null);
|
||||
@@ -33,6 +38,10 @@ public class UnixRemovableDriveMonitorTest extends TestCase {
|
||||
|
||||
@Test
|
||||
public void testOneCallbackPerFile() throws Exception {
|
||||
if(!OsUtils.isLinux() || OsUtils.isMacLeopardOrNewer()) {
|
||||
System.err.println("Warning: Skipping test");
|
||||
return;
|
||||
}
|
||||
// Create a callback that will wait for two files before stopping
|
||||
final List<File> detected = new ArrayList<File>();
|
||||
final CountDownLatch latch = new CountDownLatch(2);
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.sf.briar.util;
|
||||
public class OsUtils {
|
||||
|
||||
private static final String os = System.getProperty("os.name");
|
||||
private static final String version = System.getProperty("os.version");
|
||||
|
||||
public static boolean isWindows() {
|
||||
return os.indexOf("Windows") != -1;
|
||||
@@ -12,6 +13,19 @@ public class OsUtils {
|
||||
return os.indexOf("Mac OS") != -1;
|
||||
}
|
||||
|
||||
public static boolean isMacLeopardOrNewer() {
|
||||
if(!isMac() || version == null) return false;
|
||||
try {
|
||||
String[] v = version.split("\\.");
|
||||
if(v.length != 3) return false;
|
||||
int major = Integer.parseInt(v[0]);
|
||||
int minor = Integer.parseInt(v[1]);
|
||||
return major >= 10 && minor >= 5;
|
||||
} catch(NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isLinux() {
|
||||
return os.indexOf("Linux") != -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user