From 816317b8a6cbf4e95151ed0ab0bc989a8e4aee7e Mon Sep 17 00:00:00 2001 From: Timothy Wall Date: Wed, 9 Nov 2011 07:30:18 -0500 Subject: [PATCH] re-enable WCE failing tests, fixes to allow proper phoneME operation w/r/t AWT classes --- src/com/sun/jna/Native.java | 71 ++++++++++++++-------- src/com/sun/jna/Platform.java | 9 +++ src/com/sun/jna/Structure.java | 24 +++++--- src/com/sun/jna/overview.html | 2 +- test/com/sun/jna/ArgumentsMarshalTest.java | 3 +- test/com/sun/jna/CallbacksTest.java | 5 +- test/com/sun/jna/LibraryLoadTest.java | 48 +++++++++------ test/com/sun/jna/NativeTest.java | 15 ++--- test/com/sun/jna/ReturnTypesTest.java | 3 +- test/com/sun/jna/StructureTest.java | 2 +- w32ce-test.lnk | 2 +- 11 files changed, 114 insertions(+), 70 deletions(-) diff --git a/src/com/sun/jna/Native.java b/src/com/sun/jna/Native.java index 14f87fa41f..c26bfac23e 100644 --- a/src/com/sun/jna/Native.java +++ b/src/com/sun/jna/Native.java @@ -16,6 +16,10 @@ import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.Window; + +import java.nio.Buffer; +import java.nio.ByteBuffer; + import java.io.File; import java.io.FilenameFilter; import java.io.FileOutputStream; @@ -32,8 +36,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.nio.Buffer; -import java.nio.ByteBuffer; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; @@ -199,7 +201,7 @@ private Native() { } * NOTE: On platforms which support signals (non-Windows), JNA uses * signals to trap errors. This may interfere with the JVM's own use of * signals. When protected mode is enabled, you should make use of the - * jsig library, if available (see Signal Chaining). + * jsig library, if available (see Signal Chaining). * In short, set the environment variable LD_PRELOAD to the * path to libjsig.so in your JRE lib directory * (usually ${java.home}/lib/${os.arch}/libjsig.so) before launching your @@ -237,7 +239,7 @@ private Native() { } * @throws HeadlessException if the current VM is running headless */ public static long getWindowID(Window w) throws HeadlessException { - return getComponentID(w); + return AWT.getWindowID(w); } /** Utility method to get the native window ID for a heavyweight Java @@ -247,25 +249,7 @@ public static long getWindowID(Window w) throws HeadlessException { * @throws HeadlessException if the current VM is running headless */ public static long getComponentID(Component c) throws HeadlessException { - if (GraphicsEnvironment.isHeadless()) { - throw new HeadlessException("No native windows when headless"); - } - if (c.isLightweight()) { - throw new IllegalArgumentException("Component must be heavyweight"); - } - if (!c.isDisplayable()) - throw new IllegalStateException("Component must be displayable"); - // On X11 VMs prior to 1.5, the window must be visible - if (Platform.isX11() - && System.getProperty("java.version").startsWith("1.4")) { - if (!c.isVisible()) { - throw new IllegalStateException("Component must be visible"); - } - } - // By this point, we're certain that Toolkit.loadLibraries() has - // been called, thus avoiding AWT/JAWT link errors - // (see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6539705). - return getWindowHandle0(c); + return AWT.getComponentID(c); } /** Utility method to get the native window pointer for a Java @@ -275,7 +259,7 @@ public static long getComponentID(Component c) throws HeadlessException { * @throws HeadlessException if the current VM is running headless */ public static Pointer getWindowPointer(Window w) throws HeadlessException { - return getComponentPointer(w); + return new Pointer(AWT.getWindowID(w)); } /** Utility method to get the native window pointer for a heavyweight Java @@ -285,10 +269,10 @@ public static Pointer getWindowPointer(Window w) throws HeadlessException { * @throws HeadlessException if the current VM is running headless */ public static Pointer getComponentPointer(Component c) throws HeadlessException { - return new Pointer(getComponentID(c)); + return new Pointer(AWT.getComponentID(c)); } - private static native long getWindowHandle0(Component c); + static native long getWindowHandle0(Component c); /** Convert a direct {@link Buffer} into a {@link Pointer}. * @throws IllegalArgumentException if the buffer is not direct. @@ -1721,7 +1705,7 @@ static Pointer getPointer(long addr) { * Get a direct ByteBuffer mapped to the memory pointed to by the pointer. * This method calls through to the JNA NewDirectByteBuffer method. * - * @param addr byte offset from pointer to start the buffer + * @param addr base address of the JNA-originated memory * @param length Length of ByteBuffer * @return a direct ByteBuffer that accesses the memory being pointed to, */ @@ -1741,4 +1725,37 @@ static Pointer getPointer(long addr) { public static void detach(boolean detach) { setLastError(detach ? THREAD_DETACH : THREAD_LEAVE_ATTACHED); } + + /** Provides separation of JAWT functionality for the sake of J2ME + * ports which do not include AWT support. + */ + private static class AWT { + static long getWindowID(Window w) throws HeadlessException { + return getComponentID(w); + } + // Declaring the argument as Object rather than Component avoids class not + // found errors on phoneME foundation profile. + static long getComponentID(Object o) throws HeadlessException { + if (GraphicsEnvironment.isHeadless()) { + throw new HeadlessException("No native windows when headless"); + } + Component c = (Component)o; + if (c.isLightweight()) { + throw new IllegalArgumentException("Component must be heavyweight"); + } + if (!c.isDisplayable()) + throw new IllegalStateException("Component must be displayable"); + // On X11 VMs prior to 1.5, the window must be visible + if (Platform.isX11() + && System.getProperty("java.version").startsWith("1.4")) { + if (!c.isVisible()) { + throw new IllegalStateException("Component must be visible"); + } + } + // By this point, we're certain that Toolkit.loadLibraries() has + // been called, thus avoiding AWT/JAWT link errors + // (see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6539705). + return Native.getWindowHandle0(c); + } + } } diff --git a/src/com/sun/jna/Platform.java b/src/com/sun/jna/Platform.java index 4d96b80546..38072d9900 100644 --- a/src/com/sun/jna/Platform.java +++ b/src/com/sun/jna/Platform.java @@ -21,6 +21,7 @@ public final class Platform { public static final int WINDOWSCE = 6; public static final boolean HAS_BUFFERS; + public static final boolean HAS_AWT; public static final String MATH_LIBRARY_NAME; public static final String C_LIBRARY_NAME; @@ -52,6 +53,14 @@ else if (osName.startsWith("OpenBSD")) { else { osType = UNSPECIFIED; } + boolean hasAWT = false; + try { + Class.forName("java.awt.Component"); + hasAWT = true; + } + catch(ClassNotFoundException e) { + } + HAS_AWT = hasAWT; boolean hasBuffers = false; try { Class.forName("java.nio.Buffer"); diff --git a/src/com/sun/jna/Structure.java b/src/com/sun/jna/Structure.java index 0ffb80832e..3727d0e7d8 100644 --- a/src/com/sun/jna/Structure.java +++ b/src/com/sun/jna/Structure.java @@ -487,15 +487,25 @@ Object getField(StructField structField) { } } - // WARNING: phoneME fails to set a 'final' field even after calling - // setAccessible(true) on the field void setField(StructField structField, Object value) { + setField(structField, value, false); + } + + void setField(StructField structField, Object value, boolean overrideFinal) { try { structField.field.set(this, value); } catch(IllegalAccessException e) { - if (Modifier.isFinal(structField.field.getModifiers())) { - throw new UnsupportedOperationException("Read-only (final) structure fields may only be updated from native memory (field '" + structField.name + "' within " + getClass() + ")"); + int modifiers = structField.field.getModifiers(); + if (Modifier.isFinal(modifiers)) { + if (overrideFinal) { + // WARNING: setAccessible(true) on phoneME does *not* allow overwriting of + // a final field. It also ignores any changes made to the + // field's modifiers (temporarily removing the final flag + // on the field does not work). + throw new UnsupportedOperationException("This VM does not support Structures with final fields (field '" + structField.name + "' within " + getClass() + ")"); + } + throw new UnsupportedOperationException("Attempt to write to read-only field '" + structField.name + "' within " + getClass()); } throw new Error("Unexpectedly unable to write to field '" + structField.name + "' within " + getClass() @@ -560,10 +570,7 @@ Object readField(StructField structField) { } // Update the value on the field - if (Modifier.isFinal(structField.field.getModifiers())) { - structField.field.setAccessible(true); - } - setField(structField, result); + setField(structField, result, true); return result; } @@ -785,6 +792,7 @@ int calculateSize(boolean force) { structField.isVolatile = Modifier.isVolatile(modifiers); structField.isReadOnly = Modifier.isFinal(modifiers); if (Modifier.isFinal(modifiers)) { + // In most cases, this allows overriding the value of final fields field.setAccessible(true); } structField.field = field; diff --git a/src/com/sun/jna/overview.html b/src/com/sun/jna/overview.html index 6aae01e36f..fcf8a00fe6 100644 --- a/src/com/sun/jna/overview.html +++ b/src/com/sun/jna/overview.html @@ -698,7 +698,7 @@

Library Global Data

VM Crash Protection

It is not uncommon when defining a new library and writing tests to encounter memory access errors which crash the VM. These are often caused by improper mappings or invalid arguments passed to the native library. To generate Java errors instead of crashing the VM, call {@link com.sun.jna.Native#setProtected Native.setProtected(true)}. Not all platforms support this protection; if not, the value of {@link com.sun.jna.Native#isProtected} will remain false.

-NOTE: When protected mode is enabled, you should make use of the jsig library, if available (see Signal Chaining) to avoid interfering with the JVM's use of signals. In short, set the environment variable LD_PRELOAD (or LD_PRELOAD_64) to the path to libjsig.so in your JRE lib directory (usually ${java.home}/lib/${os.arch}/libjsig.so) before launching your Java application. +NOTE: When protected mode is enabled, you should make use of the jsig library, if available (see Signal Chaining) to avoid interfering with the JVM's use of signals. In short, set the environment variable LD_PRELOAD (or LD_PRELOAD_64) to the path to libjsig.so in your JRE lib directory (usually ${java.home}/lib/${os.arch}/libjsig.so) before launching your Java application.

diff --git a/test/com/sun/jna/ArgumentsMarshalTest.java b/test/com/sun/jna/ArgumentsMarshalTest.java index 17552d8d6a..ea5e964610 100644 --- a/test/com/sun/jna/ArgumentsMarshalTest.java +++ b/test/com/sun/jna/ArgumentsMarshalTest.java @@ -545,8 +545,7 @@ public void testDisableAutoSynch() { assertEquals("Auto read should be disabled", EXPECTED, s.field); } - // w32ce crash - public void XFAIL_WCE_testUnionByValueCallbackArgument() throws Exception{ + public void testUnionByValueCallbackArgument() throws Exception{ TestLibrary.TestUnion arg = new TestLibrary.TestUnion(); arg.setType(String.class); final String VALUE = getName(); diff --git a/test/com/sun/jna/CallbacksTest.java b/test/com/sun/jna/CallbacksTest.java index 729cedcb0b..b9108c8655 100644 --- a/test/com/sun/jna/CallbacksTest.java +++ b/test/com/sun/jna/CallbacksTest.java @@ -546,7 +546,7 @@ public String callback(String arg) { assertEquals("Wrong String return", VALUE, value); } - public void XFAIL_WCE_testStringCallbackMemoryReclamation() throws InterruptedException { + public void testStringCallbackMemoryReclamation() throws InterruptedException { TestLibrary.StringCallback cb = new TestLibrary.StringCallback() { public String callback(String arg) { return arg; @@ -623,8 +623,7 @@ public int callback(int arg, IntByReference result) { assertEquals("Wrong value in by reference memory", VALUE, ref.getValue()); } - // crash - public void XFAIL_WCE_testCallCallbackWithStructByValue() { + public void testCallCallbackWithStructByValue() { final TestStructure.ByValue s = new TestStructure.ByValue(); final TestStructure innerResult = new TestStructure(); TestStructure.TestCallback cb = new TestStructure.TestCallback() { diff --git a/test/com/sun/jna/LibraryLoadTest.java b/test/com/sun/jna/LibraryLoadTest.java index d2e09ce8d7..846192f4ea 100644 --- a/test/com/sun/jna/LibraryLoadTest.java +++ b/test/com/sun/jna/LibraryLoadTest.java @@ -29,21 +29,26 @@ public class LibraryLoadTest extends TestCase { + (Platform.is64Bit() ? "-d64" : "")); public void testLoadJNALibrary() { - assertTrue("Point size should never be zero", Pointer.SIZE > 0); + assertTrue("Pointer size should never be zero", Pointer.SIZE > 0); } public void testLoadJAWT() { + if (!Platform.HAS_AWT) return; + if (GraphicsEnvironment.isHeadless()) return; - Frame f = new Frame(getName()); - f.pack(); - try { - // FIXME: this works as a test, but fails in ShapedWindowDemo - // if the JAWT load workaround is not used - Native.getWindowPointer(f); - } - finally { - f.dispose(); + // Encapsulate in a separate class to avoid class loading issues where + // AWT is unavailable + AWT.loadJAWT(getName()); + } + + public void testLoadAWTAfterJNA() { + if (!Platform.HAS_AWT) return; + + if (GraphicsEnvironment.isHeadless()) return; + + if (Pointer.SIZE > 0) { + Toolkit.getDefaultToolkit(); } } @@ -56,14 +61,6 @@ public static interface CLibrary extends Library { int geteuid(); } - public void testLoadAWTAfterJNA() { - if (GraphicsEnvironment.isHeadless()) return; - - if (Pointer.SIZE > 0) { - Toolkit.getDefaultToolkit(); - } - } - private Object load() { return Native.loadLibrary(Platform.C_LIBRARY_NAME, CLibrary.class); } @@ -162,6 +159,21 @@ public void testLoadProperCLibraryVersion() { lib.getpwuid(lib.geteuid())); } + private static class AWT { + public static void loadJAWT(String name) { + Frame f = new Frame(name); + f.pack(); + try { + // FIXME: this works as a test, but fails in ShapedWindowDemo + // if the JAWT load workaround is not used + Native.getWindowPointer(f); + } + finally { + f.dispose(); + } + } + } + public static void main(String[] args) { junit.textui.TestRunner.run(LibraryLoadTest.class); } diff --git a/test/com/sun/jna/NativeTest.java b/test/com/sun/jna/NativeTest.java index 249118e76e..ca3cc82cd6 100644 --- a/test/com/sun/jna/NativeTest.java +++ b/test/com/sun/jna/NativeTest.java @@ -23,7 +23,7 @@ public class NativeTest extends TestCase { public void testLongStringGeneration() { StringBuffer buf = new StringBuffer(); - final int MAX = 2000000; + final int MAX = Platform.isWindowsCE() ? 200000 : 2000000; for (int i=0;i < MAX;i++) { buf.append('a'); } @@ -345,21 +345,22 @@ public static void main(String[] args) { if (args.length == 1 && "all".equals(args[0])) { args = new String[] { "com.sun.jna.NativeTest", - "com.sun.jna.NativeLibraryTest", + "com.sun.jna.NativeLibraryTest", // 1 wce failure "com.sun.jna.PointerTest", "com.sun.jna.MemoryTest", "com.sun.jna.LibraryLoadTest", "com.sun.jna.ArgumentsMarshalTest", - "com.sun.jna.ReturnTypesTest", + "com.sun.jna.ReturnTypesTest", "com.sun.jna.TypeMapperTest", "com.sun.jna.ByReferenceArgumentsTest", "com.sun.jna.LastErrorTest", - "com.sun.jna.StructureTest", + "com.sun.jna.StructureTest",// 1 wce failure (ro) "com.sun.jna.StructureByValueTest", "com.sun.jna.UnionTest", "com.sun.jna.IntegerTypeTest", "com.sun.jna.VMCrashProtectionTest", - "com.sun.jna.CallbacksTest", + "com.sun.jna.CallbacksTest", // 1 wce failure (String + // memory reclamation) "com.sun.jna.JNAUnloadTest", "com.sun.jna.DirectTest", "com.sun.jna.DirectArgumentsMarshalTest", @@ -376,8 +377,8 @@ public static void main(String[] args) { try { junit.textui.TestRunner.run(Class.forName(args[i])); } - catch(ClassNotFoundException e) { - System.err.println("No such class: " + args[i]); + catch(Throwable e) { + e.printStackTrace(); } } try { Thread.sleep(300000); } catch(Exception e) { } diff --git a/test/com/sun/jna/ReturnTypesTest.java b/test/com/sun/jna/ReturnTypesTest.java index 1384c311ad..313f78c6a9 100644 --- a/test/com/sun/jna/ReturnTypesTest.java +++ b/test/com/sun/jna/ReturnTypesTest.java @@ -227,8 +227,7 @@ public void testInvokeNullStructure() { assertNull("Expect null structure return", s); } - // w32ce crash - public void XFAIL_WCE_testReturnSmallStructureByValue() { + public void testReturnSmallStructureByValue() { TestSmallStructure s = lib.returnSmallStructureByValue(); assertNotNull("Returned structure must not be null", s); assertEquals("Wrong char field value (1)", 1, s.c1); diff --git a/test/com/sun/jna/StructureTest.java b/test/com/sun/jna/StructureTest.java index a2017b143c..3af31af321 100644 --- a/test/com/sun/jna/StructureTest.java +++ b/test/com/sun/jna/StructureTest.java @@ -852,7 +852,7 @@ private ROStructure avoidConstantFieldOptimization(ROStructure s) { return s; } - // This functionality is no longer supported + // wce/phoneME fails to write final field public void testReadOnlyField() { ROStructure s = new ROStructure(); s.getPointer().setInt(0, 42); diff --git a/w32ce-test.lnk b/w32ce-test.lnk index f92c5096bd..8494ea9071 100644 --- a/w32ce-test.lnk +++ b/w32ce-test.lnk @@ -1 +1 @@ -255#"\storage card\phoneme\personal\bin\cvm.exe" -Djna.boot.library.path="\storage card" -Djna.library.path="\storage card" -cp "\storage card\test.jar;\storage card\junit.jar" com.sun.jna.NativeTest com.sun.jna.LibraryLoadTest +255#"\storage card\phoneme\personal\bin\cvm.exe" -Djna.boot.library.path="\storage card" -Djna.library.path="\storage card" -cp "\storage card\test.jar;\storage card\junit.jar" com.sun.jna.NativeTest all