changeset 10583:a8fa94609c3a

8076182: Open Source Java Access Bridge - Create Patch for JEP C127 8055831 Summary: move files from open to closed Reviewed-by: erikj, serb, azvegint Contributed-by: peter.brunet@oracle.com
author ptbrunet
date Tue, 31 Mar 2015 18:39:00 +0400
parents 2c6ed934f83b
children db28516c0691
files make/CompileJavaClasses.gmk make/CompileLaunchers.gmk make/CopyFiles.gmk make/CreateJars.gmk make/gensrc/GensrcMisc.gmk make/lib/PlatformLibraries.gmk src/windows/classes/com/sun/java/accessibility/32bit/AccessBridgeLoader.java src/windows/classes/com/sun/java/accessibility/64bit/AccessBridgeLoader.java src/windows/classes/com/sun/java/accessibility/AccessBridge.java src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedRelation.java src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedRelationConstants.java src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedRole.java src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedRoleConstants.java src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedState.java src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedStateConstants.java src/windows/classes/com/sun/java/accessibility/legacy/AccessBridgeLoader.java src/windows/classes/com/sun/java/accessibility/util/AWTEventMonitor.java src/windows/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java src/windows/classes/com/sun/java/accessibility/util/AccessibilityListenerList.java src/windows/classes/com/sun/java/accessibility/util/EventID.java src/windows/classes/com/sun/java/accessibility/util/EventQueueMonitor.java src/windows/classes/com/sun/java/accessibility/util/GUIInitializedListener.java src/windows/classes/com/sun/java/accessibility/util/GUIInitializedMulticaster.java src/windows/classes/com/sun/java/accessibility/util/SwingEventMonitor.java src/windows/classes/com/sun/java/accessibility/util/TopLevelWindowListener.java src/windows/classes/com/sun/java/accessibility/util/TopLevelWindowMulticaster.java src/windows/classes/com/sun/java/accessibility/util/Translator.java src/windows/classes/com/sun/java/accessibility/util/java/awt/ButtonTranslator.java src/windows/classes/com/sun/java/accessibility/util/java/awt/CheckboxTranslator.java src/windows/classes/com/sun/java/accessibility/util/java/awt/ChoiceTranslator.java src/windows/classes/com/sun/java/accessibility/util/java/awt/LabelTranslator.java src/windows/classes/com/sun/java/accessibility/util/java/awt/ListTranslator.java src/windows/classes/com/sun/java/accessibility/util/java/awt/TextComponentTranslator.java src/windows/classes/com/sun/java/accessibility/util/package-info.java src/windows/native/sun/bridge/AccessBridgeATInstance.cpp src/windows/native/sun/bridge/AccessBridgeATInstance.h src/windows/native/sun/bridge/AccessBridgeCallbacks.h src/windows/native/sun/bridge/AccessBridgeCalls.c src/windows/native/sun/bridge/AccessBridgeCalls.h src/windows/native/sun/bridge/AccessBridgeDebug.cpp src/windows/native/sun/bridge/AccessBridgeDebug.h src/windows/native/sun/bridge/AccessBridgeEventHandler.cpp src/windows/native/sun/bridge/AccessBridgeEventHandler.h src/windows/native/sun/bridge/AccessBridgeJavaEntryPoints.cpp src/windows/native/sun/bridge/AccessBridgeJavaEntryPoints.h src/windows/native/sun/bridge/AccessBridgeJavaVMInstance.cpp src/windows/native/sun/bridge/AccessBridgeJavaVMInstance.h src/windows/native/sun/bridge/AccessBridgeMessageQueue.cpp src/windows/native/sun/bridge/AccessBridgeMessageQueue.h src/windows/native/sun/bridge/AccessBridgeMessages.cpp src/windows/native/sun/bridge/AccessBridgeMessages.h src/windows/native/sun/bridge/AccessBridgePackages.h src/windows/native/sun/bridge/AccessBridgeStatusWindow.RC src/windows/native/sun/bridge/AccessBridgeWindowsEntryPoints.cpp src/windows/native/sun/bridge/AccessBridgeWindowsEntryPoints.h src/windows/native/sun/bridge/JAWTAccessBridge.cpp src/windows/native/sun/bridge/JAWTAccessBridge.h src/windows/native/sun/bridge/JavaAccessBridge.cpp src/windows/native/sun/bridge/JavaAccessBridge.h src/windows/native/sun/bridge/WinAccessBridge.DEF src/windows/native/sun/bridge/WinAccessBridge.cpp src/windows/native/sun/bridge/WinAccessBridge.h src/windows/native/sun/bridge/accessBridgeResource.h src/windows/native/sun/bridge/accessibility.properties src/windows/native/sun/bridge/jabswitch.cpp src/windows/native/sun/bridge/jabswitch.manifest src/windows/native/sun/bridge/jabswitch_manifest.rc src/windows/native/sun/bridge/resource.h
diffstat 68 files changed, 35114 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/make/CompileJavaClasses.gmk	Mon Mar 30 19:33:25 2015 +0300
+++ b/make/CompileJavaClasses.gmk	Tue Mar 31 18:39:00 2015 +0400
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -64,7 +64,10 @@
     # This gets built on unix platforms implicitly in the old build even though
     # it's excluded in the closed build.
     EXCLUDES += sun/java2d/pisces
+  endif
+endif
 
+ifeq ($(OPENJDK_TARGET_OS), windows)
     # AccessBridge is compiled separately below.
     EXFILES += AccessBridge.java \
         AccessBridgeLoader.java \
@@ -73,8 +76,6 @@
     EXCLUDES += com/sun/java/accessibility/extensions
   endif
 
-endif
-
 ifneq ($(OPENJDK_TARGET_OS), solaris)
   # Exclude Solaris nio and two security related files in src/share/classes
   EXFILES += SolarisAclFileAttributeView.java \
@@ -272,7 +273,7 @@
 
 ifndef OPENJDK
   CLOSED_SRC_DIRS := $(JDK_TOPDIR)/src/closed/share/classes \
-      $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS_API_DIR)/classes
+      $(wildcard $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS_API_DIR)/classes)
 endif
 
 MACOSX_SRC_DIRS :=
@@ -379,7 +380,6 @@
 
 ##########################################################################################
 
-ifndef OPENJDK
   ifeq ($(OPENJDK_TARGET_OS), windows)
     ifeq ($(OPENJDK_TARGET_CPU_BITS), 32)
       $(eval $(call SetupJavaCompilation,BUILD_ACCESSBRIDGE_32, \
@@ -413,7 +413,6 @@
 
     endif
   endif
-endif
 
 ##########################################################################################
 
--- a/make/CompileLaunchers.gmk	Mon Mar 30 19:33:25 2015 +0300
+++ b/make/CompileLaunchers.gmk	Tue Mar 31 18:39:00 2015 +0400
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -659,11 +659,10 @@
 ##########################################################################################
 # jabswitch
 
-ifndef OPENJDK
   ifeq ($(OPENJDK_TARGET_OS), windows)
 
     $(eval $(call SetupNativeCompilation,BUILD_JABSWITCH, \
-        SRC := $(JDK_TOPDIR)/src/closed/windows/native/sun/bridge, \
+      SRC := $(JDK_TOPDIR)/src/windows/native/sun/bridge, \
         INCLUDE_FILES := jabswitch.cpp, \
         LANG := C++, \
         CFLAGS := $(filter-out -Zc:wchar_t-, $(CFLAGS_JDKEXE)) -Zc:wchar_t \
@@ -675,17 +674,16 @@
         OUTPUT_DIR := $(JDK_OUTPUTDIR)/bin, \
         PROGRAM := jabswitch, \
         DEBUG_SYMBOLS := true, \
-        VERSIONINFO_RESOURCE := $(JDK_TOPDIR)/src/closed/windows/native/sun/bridge/AccessBridgeStatusWindow.rc, \
+      VERSIONINFO_RESOURCE := $(JDK_TOPDIR)/src/windows/native/sun/bridge/AccessBridgeStatusWindow.rc, \
         RC_FLAGS := $(RC_FLAGS) \
             -D "JDK_FNAME=jabswitch.exe" \
             -D "JDK_INTERNAL_NAME=jabswitch" \
             -D "JDK_FTYPE=0x01L", \
-        MANIFEST := $(JDK_TOPDIR)/src/closed/windows/native/sun/bridge/jabswitch.manifest))
+      MANIFEST := $(JDK_TOPDIR)/src/windows/native/sun/bridge/jabswitch.manifest))
 
     BUILD_LAUNCHERS += $(BUILD_JABSWITCH)
 
   endif
-endif
 
 ##########################################################################################
 
--- a/make/CopyFiles.gmk	Mon Mar 30 19:33:25 2015 +0300
+++ b/make/CopyFiles.gmk	Tue Mar 31 18:39:00 2015 +0400
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -55,7 +55,6 @@
 
 ##########################################################################################
 
-ifndef OPENJDK
   ifeq ($(OPENJDK_TARGET_OS), windows)
     COPY_FILES += $(OPENJDK_TARGET_OS_INCLUDE)/bridge/AccessBridgeCallbacks.h \
         $(OPENJDK_TARGET_OS_INCLUDE)/bridge/AccessBridgeCalls.h \
@@ -64,14 +63,12 @@
         $(JDK_OUTPUTDIR)/lib/accessibility.properties
 
     $(OPENJDK_TARGET_OS_INCLUDE)/bridge/%: \
-        $(JDK_TOPDIR)/src/closed/windows/native/sun/bridge/%
+      $(JDK_TOPDIR)/src/windows/native/sun/bridge/%
 		$(install-file)
 
     $(JDK_OUTPUTDIR)/lib/accessibility.properties: \
-        $(JDK_TOPDIR)/src/closed/windows/native/sun/bridge/accessibility.properties
+      $(JDK_TOPDIR)/src/windows/native/sun/bridge/accessibility.properties
 		$(install-file)
-
-  endif
 endif
 
 ##########################################################################################
--- a/make/CreateJars.gmk	Mon Mar 30 19:33:25 2015 +0300
+++ b/make/CreateJars.gmk	Tue Mar 31 18:39:00 2015 +0400
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -650,7 +650,6 @@
 
 ##########################################################################################
 
-ifndef OPENJDK
   ifeq ($(OPENJDK_TARGET_OS), windows)
 
     $(eval $(call SetupArchive,BUILD_JACCESS_JAR, , \
@@ -686,7 +685,6 @@
       JARS += $(IMAGES_OUTPUTDIR)/lib/ext/access-bridge-64.jar
     endif
   endif
-endif
 
 ##########################################################################################
 
--- a/make/gensrc/GensrcMisc.gmk	Mon Mar 30 19:33:25 2015 +0300
+++ b/make/gensrc/GensrcMisc.gmk	Tue Mar 31 18:39:00 2015 +0400
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -174,11 +174,10 @@
 
 ##########################################################################################
 
-ifndef OPENJDK
   ifeq ($(OPENJDK_TARGET_OS), windows)
 
     AB_GENSRC_DIR := $(JDK_OUTPUTDIR)/gensrc_ab
-    AB_SRC_DIR := $(JDK_TOPDIR)/src/closed/windows/classes/com/sun/java/accessibility
+  AB_SRC_DIR := $(JDK_TOPDIR)/src/windows/classes/com/sun/java/accessibility
 
     ifeq ($(OPENJDK_TARGET_CPU_BITS), 32)
       $(AB_GENSRC_DIR)/32bit/com/sun/java/accessibility/AccessBridgeLoader.java: \
@@ -216,6 +215,5 @@
 
     endif
   endif
-endif
 
 ##########################################################################################
--- a/make/lib/PlatformLibraries.gmk	Mon Mar 30 19:33:25 2015 +0300
+++ b/make/lib/PlatformLibraries.gmk	Tue Mar 31 18:39:00 2015 +0400
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -127,10 +127,9 @@
 
 ##########################################################################################
 
-ifndef OPENJDK
   ifeq ($(OPENJDK_TARGET_OS), windows)
 
-    ACCESSBRIDGE_SRCDIR := $(JDK_TOPDIR)/src/closed/windows/native/sun/bridge
+  ACCESSBRIDGE_SRCDIR := $(JDK_TOPDIR)/src/windows/native/sun/bridge
 
     define SetupAccessBridge
       # Parameter 1 Suffix
@@ -149,8 +148,7 @@
           LDFLAGS := $(LDFLAGS_JDKLIB) kernel32.lib user32.lib gdi32.lib \
               winspool.lib jawt.lib comdlg32.lib advapi32.lib shell32.lib \
               ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib \
-              -subsystem:windows -machine:$2 \
-              -def:$(ACCESSBRIDGE_SRCDIR)/JAWTAccessBridge.DEF, \
+            -subsystem:windows -machine:$2, \
           VERSIONINFO_RESOURCE := $(ACCESSBRIDGE_SRCDIR)/AccessBridgeStatusWindow.rc, \
           RC_FLAGS := $(RC_FLAGS) \
               -D "JDK_FNAME=JAWTAccessBridge$1.dll" \
@@ -159,7 +157,8 @@
           OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libjawtaccessbridge$1, \
           DEBUG_SYMBOLS := true)
 
-      $$(BUILD_JAWTACCESSBRIDGE$1): $(JDK_OUTPUTDIR)/lib/$(LIBRARY_PREFIX)jawt$(STATIC_LIBRARY_SUFFIX)
+    $$(BUILD_JAWTACCESSBRIDGE$1): \
+        $(JDK_OUTPUTDIR)/lib/$(LIBRARY_PREFIX)jawt$(STATIC_LIBRARY_SUFFIX)
 
       $(call SetupNativeCompilation,BUILD_JAVAACCESSBRIDGE$1, \
           LIBRARY = JavaAccessBridge$1, \
@@ -175,8 +174,7 @@
           LDFLAGS := $(LDFLAGS_JDKLIB) kernel32.lib user32.lib gdi32.lib \
               winspool.lib comdlg32.lib advapi32.lib shell32.lib \
               ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib \
-              -subsystem:windows -machine:$2 \
-              -def:$(ACCESSBRIDGE_SRCDIR)/JavaAccessBridge.DEF, \
+            -subsystem:windows -machine:$2, \
           VERSIONINFO_RESOURCE := $(ACCESSBRIDGE_SRCDIR)/AccessBridgeStatusWindow.rc, \
           RC_FLAGS := $(RC_FLAGS) \
               -D "JDK_FNAME=JavaAccessBridge$1.dll" \
@@ -221,5 +219,5 @@
     else
       $(eval $(call SetupAccessBridge,-64,X64,64))
     endif
+
   endif
-endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/32bit/AccessBridgeLoader.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.java.accessibility;
+
+@jdk.Exported(false)
+abstract class AccessBridgeLoader {
+
+    /**
+     * Load JavaAccessBridge.DLL (our native half)
+     */
+    static {
+        java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Object>() {
+                public Object run() {
+                    System.loadLibrary("JavaAccessBridge-32");
+                    return null;
+                }
+            }, null, new java.lang.RuntimePermission("loadLibrary.JavaAccessBridge-32")
+        );
+    }
+
+    boolean useJAWT_DLL = false;
+
+    /**
+     * AccessBridgeLoader constructor
+     */
+    AccessBridgeLoader() {
+        // load JAWTAccessBridge.DLL on JDK 1.4.1 or later
+        // determine which version of the JDK is running
+        String version = System.getProperty("java.version");
+        if (version != null)
+            useJAWT_DLL = (version.compareTo("1.4.1") >= 0);
+
+        if (useJAWT_DLL) {
+            // Note that we have to explicitly load JAWT.DLL
+            java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Object>() {
+                    public Object run() {
+                        System.loadLibrary("JAWT");
+                        System.loadLibrary("JAWTAccessBridge-32");
+                        return null;
+                    }
+                }, null, new RuntimePermission("loadLibrary.JAWT"),
+                         new RuntimePermission("loadLibrary.JAWTAccessBridge-32")
+            );
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/64bit/AccessBridgeLoader.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.java.accessibility;
+
+@jdk.Exported(false)
+abstract class AccessBridgeLoader {
+
+    /**
+     * Load JavaAccessBridge.DLL (our native half)
+     */
+    static {
+        java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Object>() {
+                public Object run() {
+                    System.loadLibrary("JavaAccessBridge-64");
+                    return null;
+                }
+            }, null, new RuntimePermission("loadLibrary.JavaAccessBridge-64")
+        );
+    }
+
+    boolean useJAWT_DLL = false;
+
+    /**
+     * AccessBridgLoader constructor
+     */
+    AccessBridgeLoader() {
+        // load JAWTAccessBridge.DLL on JDK 1.4.1 or later
+        String version = System.getProperty("java.version");
+        if (version != null)
+            useJAWT_DLL = (version.compareTo("1.4.1") >= 0);
+
+        if (useJAWT_DLL) {
+            // Note that we have to explicitly load JAWT.DLL
+            java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Object>() {
+                    public Object run() {
+                        System.loadLibrary("JAWT");
+                        System.loadLibrary("JAWTAccessBridge-64");
+                        return null;
+                    }
+                }, null, new RuntimePermission("loadLibrary.JAWT"),
+                         new RuntimePermission("loadLibrary.JAWTAccessBridge-64")
+            );
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/AccessBridge.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,7272 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.java.accessibility;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.lang.*;
+import java.lang.reflect.*;
+
+import java.beans.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import javax.swing.tree.*;
+import javax.swing.table.*;
+import javax.swing.plaf.TreeUI;
+
+import javax.accessibility.*;
+import com.sun.java.accessibility.util.*;
+import sun.awt.AWTAccessor;
+import sun.awt.AppContext;
+import sun.awt.SunToolkit;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+/*
+ * Note: This class has to be public.  It's loaded from the VM like this:
+ *       Class.forName(atName).newInstance();
+ */
+@jdk.Exported(false)
+final public class AccessBridge extends AccessBridgeLoader {
+
+    private final String AccessBridgeVersion =
+    "AccessBridge 2.0.4";
+
+    private static AccessBridge theAccessBridge;
+    private ObjectReferences references;
+    private EventHandler eventHandler;
+    private boolean runningOnJDK1_4 = false;
+    private boolean runningOnJDK1_5 = false;
+
+    // Maps AccessibleRoles strings to AccessibleRoles.
+    private ConcurrentHashMap<String,AccessibleRole> accessibleRoleMap = new ConcurrentHashMap<>();
+
+    /**
+       If the object's role is in the following array getVirtualAccessibleName
+       will use the extended search algorithm.
+    */
+    private ArrayList<AccessibleRole> extendedVirtualNameSearchRoles = new ArrayList<>();
+    /**
+       If the role of the object's parent is in the following array
+       getVirtualAccessibleName will NOT use the extended search
+       algorithm even if the object's role is in the
+       extendedVirtualNameSearchRoles array.
+    */
+    private ArrayList<AccessibleRole> noExtendedVirtualNameSearchParentRoles = new ArrayList<>();
+
+    /**
+     * AccessBridge constructor
+     *
+     * Note: This constructor has to be public.  It's called from the VM like this:
+     *       Class.forName(atName).newInstance();
+     */
+    public AccessBridge() {
+        super();
+        theAccessBridge = this;
+        references = new ObjectReferences();
+
+        // initialize shutdown hook
+        Runtime runTime = Runtime.getRuntime();
+        shutdownHook hook = new shutdownHook();
+        runTime.addShutdownHook(new Thread(hook));
+
+        // initialize AccessibleRole map
+        initAccessibleRoleMap();
+
+        // determine which version of the JDK is running
+        String version = getJavaVersionProperty();
+        debugString("JDK version = "+version);
+        runningOnJDK1_4 = (version.compareTo("1.4") >= 0);
+        runningOnJDK1_5 = (version.compareTo("1.5") >= 0);
+
+        // initialize the methods that map HWNDs and Java top-level
+        // windows
+        if (initHWNDcalls() == true) {
+
+            // is this a JVM we can use?
+            // install JDK 1.2 and later Swing ToolKit listener
+            EventQueueMonitor.isGUIInitialized();
+
+            // start the Java event handler
+            eventHandler = new EventHandler(this);
+
+            // register for menu selection events
+            if (runningOnJDK1_4) {
+                MenuSelectionManager.defaultManager().addChangeListener(eventHandler);
+            }
+
+            // register as a NativeWindowHandler
+            addNativeWindowHandler(new DefaultNativeWindowHandler());
+
+            // start in a new thread
+            Thread abthread = new Thread(new dllRunner());
+            abthread.setDaemon(true);
+            abthread.start();
+            debugString("AccessBridge started");
+        }
+    }
+
+    /*
+     * adaptor to run the AccessBridge DLL
+     */
+    private class dllRunner implements Runnable {
+        public void run() {
+            runDLL();
+        }
+    }
+
+    /*
+     * shutdown hook
+     */
+    private class shutdownHook implements Runnable {
+
+        public void run() {
+            debugString("***** shutdownHook: shutting down...");
+            javaShutdown();
+        }
+    }
+
+
+    /*
+     * Initialize the hashtable that maps Strings to AccessibleRoles.
+     */
+    private void initAccessibleRoleMap() {
+        /*
+         * Initialize the AccessibleRoles map. This code uses methods in
+         * java.lang.reflect.* to build the map.
+         */
+        try {
+            Class<?> clAccessibleRole = Class.forName ("javax.accessibility.AccessibleRole");
+            if (null != clAccessibleRole) {
+                AccessibleRole roleUnknown = AccessibleRole.UNKNOWN;
+                Field [] fields = clAccessibleRole.getFields ();
+                int i = 0;
+                for (i = 0; i < fields.length; i ++) {
+                    Field f = fields [i];
+                    if (javax.accessibility.AccessibleRole.class == f.getType ()) {
+                        AccessibleRole nextRole = (AccessibleRole) (f.get (roleUnknown));
+                        String nextRoleString = nextRole.toDisplayString (Locale.US);
+                        accessibleRoleMap.put (nextRoleString, nextRole);
+                    }
+                }
+            }
+        } catch (Exception e) {}
+
+    /*
+      Build the extendedVirtualNameSearchRoles array list.  I chose this method
+      because some of the Accessible Roles that need to be added to it are not
+      available in all versions of the J2SE that we want to support.
+    */
+    extendedVirtualNameSearchRoles.add (AccessibleRole.COMBO_BOX);
+    try {
+        /*
+          Added in J2SE 1.4
+        */
+        extendedVirtualNameSearchRoles.add (AccessibleRole.DATE_EDITOR);
+    } catch (NoSuchFieldError e) {}
+    extendedVirtualNameSearchRoles.add (AccessibleRole.LIST);
+    extendedVirtualNameSearchRoles.add (AccessibleRole.PASSWORD_TEXT);
+    extendedVirtualNameSearchRoles.add (AccessibleRole.SLIDER);
+    try {
+        /*
+          Added in J2SE 1.3
+        */
+        extendedVirtualNameSearchRoles.add (AccessibleRole.SPIN_BOX);
+    } catch (NoSuchFieldError e) {}
+    extendedVirtualNameSearchRoles.add (AccessibleRole.TABLE);
+    extendedVirtualNameSearchRoles.add (AccessibleRole.TEXT);
+    extendedVirtualNameSearchRoles.add (AccessibleRole.UNKNOWN);
+
+    noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TABLE);
+    noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TOOL_BAR);
+    }
+
+    /**
+     * start the AccessBridge DLL running in its own thread
+     */
+    private native void runDLL();
+
+    /**
+     * debugging output (goes to OutputDebugStr())
+     */
+    private native void sendDebugString(String debugStr);
+
+    /**
+     * debugging output (goes to OutputDebugStr())
+     */
+    private void debugString(String debugStr) {
+    sendDebugString(debugStr);
+    }
+
+    /* ===== utility methods ===== */
+
+    /**
+     * decrement the reference to the object (called by native code)
+     */
+    private void decrementReference(Object o) {
+    references.decrement(o);
+    }
+
+    /**
+     * get the java.version property from the JVM
+     */
+    private String getJavaVersionProperty() {
+        String s = System.getProperty("java.version");
+        if (s != null) {
+            references.increment(s);
+            return s;
+        }
+        return null;
+    }
+
+    /**
+     * get the java.version property from the JVM
+     */
+    private String getAccessBridgeVersion() {
+        String s = new String(AccessBridgeVersion);
+        references.increment(s);
+        return s;
+    }
+
+    /* ===== HWND/Java window mapping methods ===== */
+
+    // Java toolkit methods for mapping HWNDs to Java components
+    private Method javaGetComponentFromNativeWindowHandleMethod;
+    private Method javaGetNativeWindowHandleFromComponentMethod;
+
+    // native jawt methods for mapping HWNDs to Java components
+    private native int isJAWTInstalled();
+
+    private native int jawtGetNativeWindowHandleFromComponent(Component comp);
+
+    private native Component jawtGetComponentFromNativeWindowHandle(int handle);
+
+    Toolkit toolkit;
+
+    /**
+     * map an HWND to an AWT Component
+     */
+    private boolean initHWNDcalls() {
+        Class<?> integerParemter[] = new Class<?>[1];
+        integerParemter[0] = Integer.TYPE;
+        Class<?> componentParemter[] = new Class<?>[1];
+        try {
+            componentParemter[0] = Class.forName("java.awt.Component");
+        } catch (ClassNotFoundException e) {
+            debugString("Exception: " + e.toString());
+        }
+        Object[] args = new Object[1];
+        Component c;
+        boolean returnVal = false;
+
+        toolkit = Toolkit.getDefaultToolkit();
+
+        if (useJAWT_DLL) {
+            returnVal = true;
+        } else {
+            // verify javaGetComponentFromNativeWindowHandle() method
+            // is present if JAWT.DLL is not installed
+            try {
+                javaGetComponentFromNativeWindowHandleMethod =
+                    toolkit.getClass().getMethod(
+                        "getComponentFromNativeWindowHandle", integerParemter);
+                if (javaGetComponentFromNativeWindowHandleMethod != null) {
+                    try {
+                        args[0] = new Integer(1);
+                        c = (Component) javaGetComponentFromNativeWindowHandleMethod.invoke(toolkit, args);
+                        returnVal = true;
+                    } catch (InvocationTargetException e) {
+                        debugString("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        debugString("Exception: " + e.toString());
+                    }
+                }
+            } catch (NoSuchMethodException e) {
+                debugString("Exception: " + e.toString());
+            } catch (SecurityException e) {
+                debugString("Exception: " + e.toString());
+            }
+
+            // verify getComponentFromNativeWindowHandle() method
+            // is present if JAWT.DLL is not installed
+            try {
+                javaGetNativeWindowHandleFromComponentMethod =
+                    toolkit.getClass().getMethod(
+                        "getNativeWindowHandleFromComponent", componentParemter);
+                if (javaGetNativeWindowHandleFromComponentMethod != null) {
+                    try {
+                        args[0] = new Button("OK");    // need some Component...
+                        Integer i = (Integer) javaGetNativeWindowHandleFromComponentMethod.invoke(toolkit, args);
+                        returnVal = true;
+                    } catch (InvocationTargetException e) {
+                        debugString("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        debugString("Exception: " + e.toString());
+                    } catch (Exception e) {
+                        debugString("Exception: " + e.toString());
+                    }
+                }
+            } catch (NoSuchMethodException e) {
+                debugString("Exception: " + e.toString());
+            } catch (SecurityException e) {
+                debugString("Exception: " + e.toString());
+            }
+        }
+        return returnVal;
+    }
+
+    // native window handler interface
+    private interface NativeWindowHandler {
+        public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle);
+    }
+
+    // hash table of native window handle to AccessibleContext mappings
+    static private ConcurrentHashMap<Integer,AccessibleContext> windowHandleToContextMap = new ConcurrentHashMap<>();
+
+    // hash table of AccessibleContext to native window handle mappings
+    static private ConcurrentHashMap<AccessibleContext,Integer> contextToWindowHandleMap = new ConcurrentHashMap<>();
+
+    /*
+     * adds a virtual window handler to our hash tables
+     */
+    static private void registerVirtualFrame(final Accessible a,
+                                             Integer nativeWindowHandle ) {
+        if (a != null) {
+            AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                @Override
+                public AccessibleContext call() throws Exception {
+                    return a.getAccessibleContext();
+                }
+            }, a);
+            windowHandleToContextMap.put(nativeWindowHandle, ac);
+            contextToWindowHandleMap.put(ac, nativeWindowHandle);
+        }
+    }
+
+    /*
+     * removes a virtual window handler to our hash tables
+     */
+    static private void revokeVirtualFrame(final Accessible a,
+                                           Integer nativeWindowHandle ) {
+        AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                return a.getAccessibleContext();
+            }
+        }, a);
+        windowHandleToContextMap.remove(nativeWindowHandle);
+        contextToWindowHandleMap.remove(ac);
+    }
+
+    // vector of native window handlers
+    private static Vector<NativeWindowHandler> nativeWindowHandlers = new Vector<>();
+
+    /*
+    * adds a native window handler to our list
+    */
+    private static void addNativeWindowHandler(NativeWindowHandler handler) {
+        if (handler == null) {
+            throw new IllegalArgumentException();
+        }
+        nativeWindowHandlers.addElement(handler);
+    }
+
+    /*
+     * removes a native window handler to our list
+     */
+    private static boolean removeNativeWindowHandler(NativeWindowHandler handler) {
+        if (handler == null) {
+            throw new IllegalArgumentException();
+        }
+        return nativeWindowHandlers.removeElement(handler);
+    }
+
+    /**
+     * verifies that a native window handle is a Java window
+     */
+    private boolean isJavaWindow(int nativeHandle) {
+        AccessibleContext ac = getContextFromNativeWindowHandle(nativeHandle);
+        if (ac != null) {
+            saveContextToWindowHandleMapping(ac, nativeHandle);
+            return true;
+        }
+        return false;
+    }
+
+    /*
+     * saves the mapping between an AccessibleContext and a window handle
+     */
+    private void saveContextToWindowHandleMapping(AccessibleContext ac,
+                                                  int nativeHandle) {
+        debugString("saveContextToWindowHandleMapping...");
+        if (ac == null) {
+            return;
+        }
+        if (! contextToWindowHandleMap.containsKey(ac)) {
+            debugString("saveContextToWindowHandleMapping: ac = "+ac+"; handle = "+nativeHandle);
+            contextToWindowHandleMap.put(ac, nativeHandle);
+        }
+    }
+
+    /**
+     * maps a native window handle to an Accessible Context
+     */
+    private AccessibleContext getContextFromNativeWindowHandle(int nativeHandle) {
+        // First, look for the Accessible in our hash table of
+        // virtual window handles.
+        AccessibleContext ac = windowHandleToContextMap.get(nativeHandle);
+        if(ac!=null) {
+            saveContextToWindowHandleMapping(ac, nativeHandle);
+            return ac;
+        }
+
+        // Next, look for the native window handle in our vector
+        // of native window handles.
+        int numHandlers = nativeWindowHandlers.size();
+        for (int i = 0; i < numHandlers; i++) {
+            NativeWindowHandler nextHandler = nativeWindowHandlers.elementAt(i);
+            final Accessible a = nextHandler.getAccessibleFromNativeWindowHandle(nativeHandle);
+            if (a != null) {
+                ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                    @Override
+                    public AccessibleContext call() throws Exception {
+                        return a.getAccessibleContext();
+                    }
+                }, a);
+                saveContextToWindowHandleMapping(ac, nativeHandle);
+                return ac;
+            }
+        }
+        // Not found.
+        return null;
+    }
+
+    /**
+     * maps an AccessibleContext to a native window handle
+     *     returns 0 on error
+     */
+    private int getNativeWindowHandleFromContext(AccessibleContext ac) {
+    debugString("getNativeWindowHandleFromContext: ac = "+ac);
+        try {
+            return contextToWindowHandleMap.get(ac);
+        } catch (Exception ex) {
+            return 0;
+        }
+    }
+
+    private class DefaultNativeWindowHandler implements NativeWindowHandler {
+        /*
+        * returns the Accessible associated with a native window
+        */
+        public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle) {
+            final Component c = getComponentFromNativeWindowHandle(nativeHandle);
+            if (c instanceof Accessible) {
+                AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                    @Override
+                    public AccessibleContext call() throws Exception {
+                        return c.getAccessibleContext();
+                    }
+                }, c);
+                saveContextToWindowHandleMapping(ac, nativeHandle);
+                return (Accessible)c;
+            } else {
+                return null;
+            }
+        }
+
+        /**
+        * map an HWND to an AWT Component
+        */
+        private Component getComponentFromNativeWindowHandle(int nativeHandle) {
+            if (useJAWT_DLL) {
+                debugString("*** calling jawtGetComponentFromNativeWindowHandle");
+                return jawtGetComponentFromNativeWindowHandle(nativeHandle);
+            } else {
+                debugString("*** calling javaGetComponentFromNativeWindowHandle");
+                Object[] args = new Object[1];
+                if (javaGetComponentFromNativeWindowHandleMethod != null) {
+                    try {
+                        args[0] = nativeHandle;
+                        Object o = javaGetComponentFromNativeWindowHandleMethod.invoke(toolkit, args);
+                        if (o instanceof Accessible) {
+                            final Accessible acc=(Accessible)o;
+                            AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                                @Override
+                                public AccessibleContext call() throws Exception {
+                                    return acc.getAccessibleContext();
+                                }
+                            }, (Component)o);
+                            saveContextToWindowHandleMapping(ac,nativeHandle);
+                        }
+                        return (Component)o;
+                    } catch (InvocationTargetException | IllegalAccessException e) {
+                        debugString("Exception: " + e.toString());
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * map an AWT Component to an HWND
+     */
+    private int getNativeWindowHandleFromComponent(final Component target) {
+        if (useJAWT_DLL) {
+            debugString("*** calling jawtGetNativeWindowHandleFromComponent");
+            return jawtGetNativeWindowHandleFromComponent(target);
+        } else {
+            Object[] args = new Object[1];
+            debugString("*** calling javaGetNativeWindowHandleFromComponent");
+            if (javaGetNativeWindowHandleFromComponentMethod != null) {
+                try {
+                    args[0] = target;
+                    Integer i = (Integer) javaGetNativeWindowHandleFromComponentMethod.invoke(toolkit, args);
+                    // cache the mapping
+                    AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                        @Override
+                        public AccessibleContext call() throws Exception {
+                            return target.getAccessibleContext();
+                        }
+                    }, target);
+                    contextToWindowHandleMap.put(ac, i);
+                    return i.intValue();
+                } catch (InvocationTargetException e) {
+                    debugString("Exception: " + e.toString());
+                } catch (IllegalAccessException e) {
+                    debugString("Exception: " + e.toString());
+                }
+            }
+        }
+        return -1;
+    }
+
+    /* ===== AccessibleContext methods =====*/
+
+    /*
+     * returns the inner-most AccessibleContext in parent at Point(x, y)
+     */
+    private AccessibleContext getAccessibleContextAt(int x, int y,
+                                                    AccessibleContext parent) {
+        if (parent == null) {
+            return null;
+        }
+        if (windowHandleToContextMap != null &&
+            windowHandleToContextMap.containsValue(getRootAccessibleContext(parent))) {
+            // Path for applications that register their top-level
+            // windows with the AccessBridge (e.g., StarOffice 6.1)
+            return getAccessibleContextAt_1(x, y, parent);
+        } else {
+            // Path for applications that do not register
+            // their top-level windows with the AccessBridge
+            // (e.g., Swing/AWT applications)
+            return getAccessibleContextAt_2(x, y, parent);
+        }
+    }
+
+    /*
+     * returns the root accessible context
+     */
+    private AccessibleContext getRootAccessibleContext(final AccessibleContext ac) {
+        if (ac == null) {
+            return null;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                Accessible parent = ac.getAccessibleParent();
+                if (parent == null) {
+                    return ac;
+                }
+                Accessible tmp = parent.getAccessibleContext().getAccessibleParent();
+                while (tmp != null) {
+                    parent = tmp;
+                    tmp = parent.getAccessibleContext().getAccessibleParent();
+                }
+                return parent.getAccessibleContext();
+            }
+        }, ac);
+    }
+
+    /*
+     * StarOffice version that does not use the EventQueueMonitor
+     */
+    private AccessibleContext getAccessibleContextAt_1(final int x, final int y,
+                                                      final AccessibleContext parent) {
+        debugString(" : getAccessibleContextAt_1 called");
+        debugString("   -> x = " + x + " y = " + y + " parent = " + parent);
+
+        if (parent == null) return null;
+            final AccessibleComponent acmp = InvocationUtils.invokeAndWait(new Callable<AccessibleComponent>() {
+                @Override
+                public AccessibleComponent call() throws Exception {
+                    return parent.getAccessibleComponent();
+                }
+            }, parent);
+        if (acmp!=null) {
+            final Point loc = InvocationUtils.invokeAndWait(new Callable<Point>() {
+                @Override
+                public Point call() throws Exception {
+                    return acmp.getLocation();
+                }
+            }, parent);
+            final Accessible a = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
+                @Override
+                public Accessible call() throws Exception {
+                    return acmp.getAccessibleAt(new Point(x - loc.x, y - loc.y));
+                }
+            }, parent);
+            if (a != null) {
+                AccessibleContext foundAC = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                    @Override
+                    public AccessibleContext call() throws Exception {
+                        return a.getAccessibleContext();
+                    }
+                }, parent);
+                if (foundAC != null) {
+                    if (foundAC != parent) {
+                        // recurse down into the child
+                        return getAccessibleContextAt_1(x - loc.x, y - loc.y,
+                                                        foundAC);
+                    } else
+                        return foundAC;
+                }
+            }
+        }
+        return parent;
+    }
+
+    /*
+     * AWT/Swing version
+     */
+    private AccessibleContext getAccessibleContextAt_2(final int x, final int y,
+                                                      AccessibleContext parent) {
+        debugString("getAccessibleContextAt_2 called");
+        debugString("   -> x = " + x + " y = " + y + " parent = " + parent);
+
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                Accessible a = EventQueueMonitor.getAccessibleAt(new Point(x, y));
+                if (a != null) {
+                    AccessibleContext childAC = a.getAccessibleContext();
+                    if (childAC != null) {
+                        debugString("   returning childAC = " + childAC);
+                        return childAC;
+                    }
+                }
+                return null;
+            }
+        }, parent);
+    }
+
+    /**
+     * returns the Accessible that has focus
+     */
+    private AccessibleContext getAccessibleContextWithFocus() {
+        Component c = AWTEventMonitor.getComponentWithFocus();
+        if (c != null) {
+            final Accessible a = Translator.getAccessible(c);
+            if (a != null) {
+                AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                    @Override
+                    public AccessibleContext call() throws Exception {
+                        return a.getAccessibleContext();
+                    }
+                }, c);
+                if (ac != null) {
+                    return ac;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * returns the AccessibleName from an AccessibleContext
+     */
+    private String getAccessibleNameFromContext(final AccessibleContext ac) {
+        debugString("***** ac = "+ac.getClass());
+        if (ac != null) {
+            String s = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return ac.getAccessibleName();
+                }
+            }, ac);
+            if (s != null) {
+                references.increment(s);
+                debugString("Returning AccessibleName from Context: " + s);
+                return s;
+            } else {
+                return null;
+            }
+        } else {
+            debugString("getAccessibleNameFromContext; ac = null!");
+            return null;
+        }
+    }
+
+    /**
+     * Returns an AccessibleName for a component using an algorithm optimized
+     * for the JAWS screen reader.  This method is only intended for JAWS. All
+     * other uses are entirely optional.
+     */
+    private String getVirtualAccessibleNameFromContext(final AccessibleContext ac) {
+        if (null != ac) {
+            /*
+            Step 1:
+            =======
+            Determine if we can obtain the Virtual Accessible Name from the
+            Accessible Name or Accessible Description of the object.
+            */
+            String nameString = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return ac.getAccessibleName();
+                }
+            }, ac);
+            if ( ( null != nameString ) && ( 0 != nameString.length () ) ) {
+                debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleName.");
+                references.increment (nameString);
+                return nameString;
+            }
+            String descriptionString = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return ac.getAccessibleDescription();
+                }
+            }, ac);
+            if ( ( null != descriptionString ) && ( 0 != descriptionString.length () ) ) {
+                debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleDescription.");
+                references.increment (descriptionString);
+                return descriptionString;
+            }
+
+            debugString ("The Virtual Accessible Name was not found using AccessibleContext::getAccessibleDescription. or getAccessibleName");
+            /*
+            Step 2:
+            =======
+            Decide whether the extended name search algorithm should be
+            used for this object.
+            */
+            boolean bExtendedSearch = false;
+            AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
+                @Override
+                public AccessibleRole call() throws Exception {
+                    return ac.getAccessibleRole();
+                }
+            }, ac);
+            AccessibleContext parentContext = null;
+            AccessibleRole parentRole = AccessibleRole.UNKNOWN;
+
+            if ( extendedVirtualNameSearchRoles.contains (role) ) {
+                parentContext = getAccessibleParentFromContext (ac);
+                if ( null != parentContext ) {
+                    final AccessibleContext parentContextInnerTemp = parentContext;
+                    parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
+                        @Override
+                        public AccessibleRole call() throws Exception {
+                            return parentContextInnerTemp.getAccessibleRole();
+                        }
+                    }, ac);
+                    if ( AccessibleRole.UNKNOWN != parentRole ) {
+                        bExtendedSearch = true;
+                        if ( noExtendedVirtualNameSearchParentRoles.contains (parentRole) ) {
+                            bExtendedSearch = false;
+                        }
+                    }
+                }
+            }
+
+            if (false == bExtendedSearch) {
+                debugString ("bk -- getVirtualAccessibleNameFromContext will not use the extended name search algorithm.  role = " + role.toDisplayString (Locale.US) );
+                /*
+                Step 3:
+                =======
+                We have determined that we should not use the extended name
+                search algorithm for this object (we must obtain the name of
+                the object from the object itself and not from neighboring
+                objects).  However the object name cannot be obtained from
+                the Accessible Name or Accessible Description of the object.
+
+                Handle several special cases here that might yield a value for
+                the Virtual Accessible Name.  Return null if the object does
+                not match the criteria for any of these special cases.
+                */
+                if (AccessibleRole.LABEL == role) {
+                    /*
+                    Does the label support the Accessible Text Interface?
+                    */
+                    final AccessibleText at = InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {
+                        @Override
+                        public AccessibleText call() throws Exception {
+                            return ac.getAccessibleText();
+                        }
+                    }, ac);
+                    if (null != at) {
+                        int charCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                            @Override
+                            public Integer call() throws Exception {
+                                return at.getCharCount();
+                            }
+                        }, ac);
+                        String text = getAccessibleTextRangeFromContext (ac, 0, charCount);
+                        if (null != text) {
+                            debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Text of the LABEL object.");
+                            references.increment (text);
+                            return text;
+                        }
+                    }
+                    /*
+                    Does the label support the Accessible Icon Interface?
+                    */
+                    debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");
+                    final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
+                        @Override
+                        public AccessibleIcon[] call() throws Exception {
+                            return ac.getAccessibleIcon();
+                        }
+                    }, ac);
+                    if ( (null != ai) && (ai.length > 0) ) {
+                        String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                            @Override
+                            public String call() throws Exception {
+                                return ai[0].getAccessibleIconDescription();
+                            }
+                        }, ac);
+                        if (iconDescription != null){
+                            debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the LABEL object.");
+                            references.increment (iconDescription);
+                            return iconDescription;
+                        }
+                    } else {
+                        parentContext = getAccessibleParentFromContext (ac);
+                        if ( null != parentContext ) {
+                            final AccessibleContext parentContextInnerTemp = parentContext;
+                            parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
+                                @Override
+                                public AccessibleRole call() throws Exception {
+                                    return parentContextInnerTemp.getAccessibleRole();
+                                }
+                            }, ac);
+                            if ( AccessibleRole.TABLE == parentRole ) {
+                                int indexInParent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                                    @Override
+                                    public Integer call() throws Exception {
+                                        return ac.getAccessibleIndexInParent();
+                                    }
+                                }, ac);
+                                final AccessibleContext acTableCell = getAccessibleChildFromContext (parentContext, indexInParent);
+                                debugString ("bk -- Making a second attempt to obtain the Virtual Accessible Name from the Accessible Icon information for the Table Cell.");
+                                if (acTableCell != null) {
+                                    final AccessibleIcon [] aiRet =InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
+                                        @Override
+                                        public AccessibleIcon[] call() throws Exception {
+                                            return acTableCell.getAccessibleIcon();
+                                        }
+                                    }, ac);
+                                    if ( (null != aiRet) && (aiRet.length > 0) ) {
+                                        String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                            public String call() {
+                                                return aiRet[0].getAccessibleIconDescription ();
+                                            }
+                                        }, ac);
+                                        if (iconDescription != null){
+                                            debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the Table Cell object.");
+                                            references.increment (iconDescription);
+                                            return iconDescription;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } else if ( (AccessibleRole.TOGGLE_BUTTON == role) ||
+                            (AccessibleRole.PUSH_BUTTON == role) ) {
+                    /*
+                    Does the button support the Accessible Icon Interface?
+                    */
+                    debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");
+                    final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon []>() {
+                        public AccessibleIcon [] call() {
+                            return ac.getAccessibleIcon ();
+                        }
+                    }, ac);
+                    if ( (null != ai) && (ai.length > 0) ) {
+                        String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                            public String call() {
+                                return ai[0].getAccessibleIconDescription ();
+                            }
+                        }, ac);
+                        if (iconDescription != null){
+                            debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the TOGGLE_BUTTON or PUSH_BUTTON object.");
+                            references.increment (iconDescription);
+                            return iconDescription;
+                        }
+                    }
+                } else if ( AccessibleRole.CHECK_BOX == role ) {
+                    /*
+                    NOTE: The only case I know of in which a check box does not
+                    have a name is when that check box is contained in a table.
+
+                    In this case it would be appropriate to use the display string
+                    of the check box object as the name (in US English the display
+                    string is typically either "true" or "false").
+
+                    I am using the AccessibleValue interface to obtain the display
+                    string of the check box.  If the Accessible Value is 1, I am
+                    returning Boolean.TRUE.toString (),  If the Accessible Value is
+                    0, I am returning Boolean.FALSE.toString ().  If the Accessible
+                    Value is some other number, I will return the display string of
+                    the current numerical value of the check box.
+                    */
+                    final AccessibleValue av = InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {
+                        @Override
+                        public AccessibleValue call() throws Exception {
+                            return ac.getAccessibleValue();
+                        }
+                    }, ac);
+                    if ( null != av ) {
+                        nameString = null;
+                        Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
+                            @Override
+                            public Number call() throws Exception {
+                                return av.getCurrentAccessibleValue();
+                            }
+                        }, ac);
+                        if ( null != value ) {
+                            if ( 1 == value.intValue () ) {
+                                nameString = Boolean.TRUE.toString ();
+                            } else if ( 0 == value.intValue () ) {
+                                nameString = Boolean.FALSE.toString ();
+                            } else {
+                                nameString = value.toString ();
+                            }
+                            if ( null != nameString ) {
+                                references.increment (nameString);
+                                return nameString;
+                            }
+                        }
+                    }
+                }
+                return null;
+            }
+
+            /*
+            +
+            Beginning of the extended name search
+            +
+            */
+            final AccessibleContext parentContextOuterTemp = parentContext;
+            String parentName = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return parentContextOuterTemp.getAccessibleName();
+                }
+            }, ac);
+            String parentDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return parentContextOuterTemp.getAccessibleDescription();
+                }
+            }, ac);
+
+            /*
+            Step 4:
+            =======
+            Special case for Slider Bar objects.
+            */
+            if ( (AccessibleRole.SLIDER == role) &&
+                 (AccessibleRole.PANEL == parentRole) &&
+                 (null != parentName) ) {
+                debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Name of the SLIDER object's parent object.");
+                references.increment (parentName);
+                return parentName;
+            }
+
+            boolean bIsEditCombo = false;
+
+            AccessibleContext testContext = ac;
+            /*
+            Step 5:
+            =======
+            Special case for Edit Combo Boxes
+            */
+            if ( (AccessibleRole.TEXT == role) &&
+                 (AccessibleRole.COMBO_BOX == parentRole) ) {
+                bIsEditCombo = true;
+                if (null != parentName) {
+                    debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Name of the object's parent object.");
+                    references.increment (parentName);
+                    return parentName;
+                } else if (null != parentDescription) {
+                    debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Description of the object's parent object.");
+                    references.increment (parentDescription);
+                    return parentDescription;
+                }
+                testContext = parentContext;
+                parentRole = AccessibleRole.UNKNOWN;
+                parentContext = getAccessibleParentFromContext (testContext);
+                if ( null != parentContext ) {
+                    final AccessibleContext parentContextInnerTemp = parentContext;
+                    parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
+                        @Override
+                        public AccessibleRole call() throws Exception {
+                            return parentContextInnerTemp.getAccessibleRole();
+                        }
+                    }, ac);
+                }
+            }
+
+            /*
+            Step 6:
+            =======
+            Attempt to get the Virtual Accessible Name of the object using the
+            Accessible Relation Set Info (the LABELED_BY Accessible Relation).
+            */
+            String version = getJavaVersionProperty ();
+            if ( (null != version) && (version.compareTo ("1.3") >= 0) ) {
+                final AccessibleContext parentContextTempInner = parentContext;
+                AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {
+                    @Override
+                    public AccessibleRelationSet call() throws Exception {
+                        return parentContextTempInner.getAccessibleRelationSet();
+                    }
+                }, ac);
+                if ( ars != null && (ars.size () > 0) && (ars.contains (AccessibleRelation.LABELED_BY)) ) {
+                    AccessibleRelation labeledByRelation = ars.get (AccessibleRelation.LABELED_BY);
+                    if (labeledByRelation != null) {
+                        Object [] targets = labeledByRelation.getTarget ();
+                        Object o = targets [0];
+                        if (o instanceof Accessible) {
+                            AccessibleContext labelContext = ((Accessible)o).getAccessibleContext ();
+                            if (labelContext != null) {
+                                String labelName = labelContext.getAccessibleName ();
+                                String labelDescription = labelContext.getAccessibleDescription ();
+                                if (null != labelName) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Name Case.");
+                                    references.increment (labelName);
+                                    return labelName;
+                                } else if (null != labelDescription) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Description Case.");
+                                    references.increment (labelDescription);
+                                    return labelDescription;
+                                }
+                            }
+                        }
+                    }
+                }
+            } else {
+                debugString ("bk -- This version of Java does not support AccessibleContext::getAccessibleRelationSet.");
+            }
+
+            //Note: add AccessibleContext to use InvocationUtils.invokeAndWait
+            /*
+            Step 7:
+            =======
+            Search for a label object that is positioned either just to the left
+            or just above the object and get the Accessible Name of the Label
+            object.
+            */
+            int testIndexMax = 0;
+            int testX = 0;
+            int testY = 0;
+            int testWidth = 0;
+            int testHeight = 0;
+            int targetX = 0;
+            int targetY = 0;
+            final AccessibleContext tempContext = testContext;
+            int testIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                @Override
+                public Integer call() throws Exception {
+                    return tempContext.getAccessibleIndexInParent();
+                }
+            }, ac);
+            if ( null != parentContext ) {
+                final AccessibleContext parentContextInnerTemp = parentContext;
+                testIndexMax =  InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                    @Override
+                    public Integer call() throws Exception {
+                        return parentContextInnerTemp.getAccessibleChildrenCount() - 1;
+                    }
+                }, ac);
+            }
+            testX = getAccessibleXcoordFromContext (testContext);
+            testY = getAccessibleYcoordFromContext (testContext);
+            testWidth = getAccessibleWidthFromContext (testContext);
+            testHeight = getAccessibleHeightFromContext (testContext);
+            targetX = testX + 2;
+            targetY = testY + 2;
+
+            int childIndex = testIndex - 1;
+            /*Accessible child = null;
+            AccessibleContext childContext = null;
+            AccessibleRole childRole = AccessibleRole.UNKNOWN;*/
+            int childX = 0;
+            int childY = 0;
+            int childWidth = 0;
+            int childHeight = 0;
+            String childName = null;
+            String childDescription = null;
+            while (childIndex >= 0) {
+                final int childIndexTemp = childIndex;
+                final AccessibleContext parentContextInnerTemp = parentContext;
+                final Accessible child  =  InvocationUtils.invokeAndWait(new Callable<Accessible>() {
+                    @Override
+                    public Accessible call() throws Exception {
+                        return parentContextInnerTemp.getAccessibleChild(childIndexTemp);
+                    }
+                }, ac);
+                if ( null != child ) {
+                    final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                        @Override
+                        public AccessibleContext call() throws Exception {
+                            return child.getAccessibleContext();
+                        }
+                    }, ac);
+                    if ( null != childContext ) {
+                        AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
+                            @Override
+                            public AccessibleRole call() throws Exception {
+                                return childContext.getAccessibleRole();
+                            }
+                        }, ac);
+                        if ( AccessibleRole.LABEL == childRole ) {
+                            childX = getAccessibleXcoordFromContext (childContext);
+                            childY = getAccessibleYcoordFromContext (childContext);
+                            childWidth = getAccessibleWidthFromContext (childContext);
+                            childHeight = getAccessibleHeightFromContext (childContext);
+                            if ( (childX < testX) &&
+                                 ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
+                                childName = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                    public String call() {
+                                        return childContext.getAccessibleName ();
+                                    }
+                                }, ac);
+                                if ( null != childName ) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");
+                                    references.increment (childName);
+                                    return childName;
+                                }
+                                childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                    public String call() {
+                                        return childContext.getAccessibleDescription ();
+                                    }
+                                }, ac);
+                                if ( null != childDescription ) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");
+                                    references.increment (childDescription);
+                                    return childDescription;
+                                }
+                            } else if ( (childY < targetY) &&
+                                        ((childX <= targetX) && (targetX <= (childX + childWidth))) ) {
+                                childName = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                    public String call() {
+                                        return childContext.getAccessibleName ();
+                                    }
+                                }, ac);
+                                if ( null != childName ) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");
+                                    references.increment (childName);
+                                    return childName;
+                                }
+                                childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                    public String call() {
+                                        return childContext.getAccessibleDescription ();
+                                    }
+                                }, ac);
+                                if ( null != childDescription ) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");
+                                    references.increment (childDescription);
+                                    return childDescription;
+                                }
+                            }
+                        }
+                    }
+                }
+                childIndex --;
+            }
+            childIndex = testIndex + 1;
+            while (childIndex <= testIndexMax) {
+                final int childIndexTemp = childIndex;
+                final AccessibleContext parentContextInnerTemp = parentContext;
+                final Accessible child  =  InvocationUtils.invokeAndWait(new Callable<Accessible>() {
+                    @Override
+                    public Accessible call() throws Exception {
+                        return parentContextInnerTemp.getAccessibleChild(childIndexTemp);
+                    }
+                }, ac);
+                if ( null != child ) {
+                    final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                        @Override
+                        public AccessibleContext call() throws Exception {
+                            return child.getAccessibleContext();
+                        }
+                    }, ac);
+                    if ( null != childContext ) {
+                        AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
+                            @Override
+                            public AccessibleRole call() throws Exception {
+                                return childContext.getAccessibleRole();
+                            }
+                        }, ac);
+                        if ( AccessibleRole.LABEL == childRole ) {
+                            childX = getAccessibleXcoordFromContext (childContext);
+                            childY = getAccessibleYcoordFromContext (childContext);
+                            childWidth = getAccessibleWidthFromContext (childContext);
+                            childHeight = getAccessibleHeightFromContext (childContext);
+                            if ( (childX < testX) &&
+                                 ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
+                                childName = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                    public String call() {
+                                        return childContext.getAccessibleName ();
+                                    }
+                                }, ac);
+                                if ( null != childName ) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");
+                                    references.increment (childName);
+                                    return childName;
+                                }
+                                childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                    public String call() {
+                                        return childContext.getAccessibleDescription ();
+                                    }
+                                }, ac);
+                                if ( null != childDescription ) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");
+                                    references.increment (childDescription);
+                                    return childDescription;
+                                }
+                            } else if ( (childY < targetY) &&
+                                        ((childX <= targetX) && (targetX <= (childX + childWidth))) ) {
+                                childName = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                    public String call() {
+                                        return childContext.getAccessibleName ();
+                                    }
+                                }, ac);
+                                if ( null != childName ) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");
+                                    references.increment (childName);
+                                    return childName;
+                                }
+                                childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                    public String call() {
+                                        return childContext.getAccessibleDescription ();
+                                    }
+                                }, ac);
+                                if ( null != childDescription ) {
+                                    debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");
+                                    references.increment (childDescription);
+                                    return childDescription;
+                                }
+                            }
+                        }
+                    }
+                }
+                childIndex ++;
+            }
+            /*
+            Step 8:
+            =======
+            Special case for combo boxes and text objects, based on a
+            similar special case I found in some of our internal JAWS code.
+
+            Search for a button object that is positioned either just to the left
+            or just above the object and get the Accessible Name of the button
+            object.
+            */
+            if ( (AccessibleRole.TEXT == role) ||
+                 (AccessibleRole.COMBO_BOX == role) ||
+                 (bIsEditCombo) ) {
+                childIndex = testIndex - 1;
+                while (childIndex >= 0) {
+                    final int childIndexTemp = childIndex;
+                    final AccessibleContext parentContextInnerTemp = parentContext;
+                    final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
+                        @Override
+                        public Accessible call() throws Exception {
+                            return parentContextInnerTemp.getAccessibleChild(childIndexTemp);
+                        }
+                    }, ac);
+                    if ( null != child ) {
+                        final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                            @Override
+                            public AccessibleContext call() throws Exception {
+                                return child.getAccessibleContext();
+                            }
+                        }, ac);
+                        if ( null != childContext ) {
+                            AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
+                                @Override
+                                public AccessibleRole call() throws Exception {
+                                    return childContext.getAccessibleRole();
+                                }
+                            }, ac);
+                            if ( ( AccessibleRole.PUSH_BUTTON == childRole ) ||
+                                 ( AccessibleRole.TOGGLE_BUTTON == childRole )) {
+                                childX = getAccessibleXcoordFromContext (childContext);
+                                childY = getAccessibleYcoordFromContext (childContext);
+                                childWidth = getAccessibleWidthFromContext (childContext);
+                                childHeight = getAccessibleHeightFromContext (childContext);
+                                if ( (childX < testX) &&
+                                     ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
+                                    childName = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                        public String call() {
+                                            return childContext.getAccessibleName ();
+                                        }
+                                    }, ac);
+                                    if ( null != childName ) {
+                                        debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object.");
+                                        references.increment (childName);
+                                        return childName;
+                                    }
+                                    childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                        public String call() {
+                                            return childContext.getAccessibleDescription ();
+                                        }
+                                    }, ac);
+                                    if ( null != childDescription ) {
+                                        debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object.");
+                                        references.increment (childDescription);
+                                        return childDescription;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    childIndex --;
+                }
+                childIndex = testIndex + 1;
+                while (childIndex <= testIndexMax) {
+                    final int childIndexTemp = childIndex;
+                    final AccessibleContext parentContextInnerTemp = parentContext;
+                    final Accessible child  =  InvocationUtils.invokeAndWait(new Callable<Accessible>() {
+                        @Override
+                        public Accessible call() throws Exception {
+                            return parentContextInnerTemp.getAccessibleChild(childIndexTemp);
+                        }
+                    }, ac);
+                    if ( null != child ) {
+                        final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                            @Override
+                            public AccessibleContext call() throws Exception {
+                                return child.getAccessibleContext();
+                            }
+                        }, ac);
+                        if ( null != childContext ) {
+                            AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
+                                @Override
+                                public AccessibleRole call() throws Exception {
+                                    return childContext.getAccessibleRole();
+                                }
+                            }, ac);
+                            if ( ( AccessibleRole.PUSH_BUTTON == childRole ) ||
+                                    ( AccessibleRole.TOGGLE_BUTTON == childRole ) ) {
+                                childX = getAccessibleXcoordFromContext (childContext);
+                                childY = getAccessibleYcoordFromContext (childContext);
+                                childWidth = getAccessibleWidthFromContext (childContext);
+                                childHeight = getAccessibleHeightFromContext (childContext);
+                                if ( (childX < testX) &&
+                                     ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
+                                    childName = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                        public String call() {
+                                            return childContext.getAccessibleName();
+                                        }
+                                    }, ac);
+                                    if ( null != childName ) {
+                                        debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object.");
+                                        references.increment (childName);
+                                        return childName;
+                                    }
+                                    childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
+                                        public String call() {
+                                            return childContext.getAccessibleDescription ();
+                                        }
+                                    }, ac);
+                                    if ( null != childDescription ) {
+                                        debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object.");
+                                        references.increment (childDescription);
+                                        return childDescription;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    childIndex ++;
+                }
+            }
+            return null;
+        } else {
+            debugString ("AccessBridge::getVirtualAccessibleNameFromContext error - ac == null.");
+            return null;
+        }
+    }
+
+    /**
+     * returns the AccessibleDescription from an AccessibleContext
+     */
+    private String getAccessibleDescriptionFromContext(final AccessibleContext ac) {
+        if (ac != null) {
+            String s = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return ac.getAccessibleDescription();
+                }
+            }, ac);
+            if (s != null) {
+                references.increment(s);
+                debugString("Returning AccessibleDescription from Context: " + s);
+                return s;
+            }
+        } else {
+            debugString("getAccessibleDescriptionFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * returns the AccessibleRole from an AccessibleContext
+     */
+    private String getAccessibleRoleStringFromContext(final AccessibleContext ac) {
+        if (ac != null) {
+            AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
+                @Override
+                public AccessibleRole call() throws Exception {
+                    return ac.getAccessibleRole();
+                }
+            }, ac);
+            if (role != null) {
+                String s = role.toDisplayString(Locale.US);
+                if (s != null) {
+                    references.increment(s);
+                    debugString("Returning AccessibleRole from Context: " + s);
+                    return s;
+                }
+            }
+        } else {
+            debugString("getAccessibleRoleStringFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the AccessibleRole from an AccessibleContext in the en_US locale
+     */
+    private String getAccessibleRoleStringFromContext_en_US(final AccessibleContext ac) {
+        return getAccessibleRoleStringFromContext(ac);
+    }
+
+    /**
+     * return the AccessibleStates from an AccessibleContext
+     */
+    private String getAccessibleStatesStringFromContext(final AccessibleContext ac) {
+        if (ac != null) {
+            AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {
+                @Override
+                public AccessibleStateSet call() throws Exception {
+                    return ac.getAccessibleStateSet();
+                }
+            }, ac);
+            if (stateSet != null) {
+                String s = stateSet.toString();
+                if (s != null &&
+                    s.indexOf(AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US)) == -1) {
+                    // Indicate whether this component manages its own
+                    // children
+                    AccessibleRole role = ac.getAccessibleRole();
+                    if (role == AccessibleRole.LIST ||
+                        role == AccessibleRole.TABLE ||
+                        role == AccessibleRole.TREE) {
+                        s += ",";
+                        s += AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US);
+                    }
+                    references.increment(s);
+                    debugString("Returning AccessibleStateSet from Context: " + s);
+                    return s;
+                }
+            }
+        } else {
+            debugString("getAccessibleStatesStringFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * returns the AccessibleStates from an AccessibleContext in the en_US locale
+     */
+    private String getAccessibleStatesStringFromContext_en_US(final AccessibleContext ac) {
+        if (ac != null) {
+            AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {
+                @Override
+                public AccessibleStateSet call() throws Exception {
+                    return ac.getAccessibleStateSet();
+                }
+            }, ac);
+            if (stateSet != null) {
+                String s = "";
+                AccessibleState[] states = stateSet.toArray();
+                if (states != null && states.length > 0) {
+                    s = states[0].toDisplayString(Locale.US);
+                    for (int i = 1; i < states.length; i++) {
+                        s = s + "," + states[i].toDisplayString(Locale.US);
+                    }
+                }
+                references.increment(s);
+                debugString("Returning AccessibleStateSet en_US from Context: " + s);
+                return s;
+            }
+        }
+        debugString("getAccessibleStatesStringFromContext; ac = null");
+        return null;
+    }
+
+    /**
+     * returns the AccessibleParent from an AccessibleContext
+     */
+    private AccessibleContext getAccessibleParentFromContext(final AccessibleContext ac) {
+        if (ac==null)
+            return null;
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                Accessible a = ac.getAccessibleParent();
+                if (a != null) {
+                    AccessibleContext apc = a.getAccessibleContext();
+                    if (apc != null) {
+                        return apc;
+                    }
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+    /**
+     * returns the AccessibleIndexInParent from an AccessibleContext
+     */
+    private int getAccessibleIndexInParentFromContext(final AccessibleContext ac) {
+        if (ac==null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return ac.getAccessibleIndexInParent();
+            }
+        }, ac);
+    }
+
+    /**
+     * returns the AccessibleChild count from an AccessibleContext
+     */
+    private int getAccessibleChildrenCountFromContext(final AccessibleContext ac) {
+        if (ac==null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return ac.getAccessibleChildrenCount();
+            }
+        }, ac);
+    }
+
+    /**
+     * returns the AccessibleChild Context from an AccessibleContext
+     */
+    private AccessibleContext getAccessibleChildFromContext(final AccessibleContext ac, final int index) {
+
+        if (ac == null) {
+            return null;
+        }
+
+        final JTable table = InvocationUtils.invokeAndWait(new Callable<JTable>() {
+            @Override
+            public JTable call() throws Exception {
+                // work-around for AccessibleJTable.getCurrentAccessibleContext returning
+                // wrong renderer component when cell contains more than one component
+                Accessible parent = ac.getAccessibleParent();
+                if (parent != null) {
+                    int indexInParent = ac.getAccessibleIndexInParent();
+                    Accessible child =
+                            parent.getAccessibleContext().getAccessibleChild(indexInParent);
+                    if (child instanceof JTable) {
+                        return (JTable) child;
+                    }
+                }
+                return null;
+            }
+        }, ac);
+
+        if (table == null) {
+            return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                @Override
+                public AccessibleContext call() throws Exception {
+                    Accessible a = ac.getAccessibleChild(index);
+                    if (a != null) {
+                        return a.getAccessibleContext();
+                    }
+                    return null;
+                }
+            }, ac);
+        }
+
+        final AccessibleTable at = getAccessibleTableFromContext(ac);
+
+        final int row = getAccessibleTableRow(at, index);
+        final int column = getAccessibleTableColumn(at, index);
+
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                TableCellRenderer renderer = table.getCellRenderer(row, column);
+                if (renderer == null) {
+                    Class<?> columnClass = table.getColumnClass(column);
+                    renderer = table.getDefaultRenderer(columnClass);
+                }
+                Component component =
+                        renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),
+                                false, false, row, column);
+                if (component instanceof Accessible) {
+                    return component.getAccessibleContext();
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+    /**
+     * returns the AccessibleComponent bounds on screen from an AccessibleContext
+     */
+    private Rectangle getAccessibleBoundsOnScreenFromContext(final AccessibleContext ac) {
+        if(ac==null)
+            return null;
+        return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {
+            @Override
+            public Rectangle call() throws Exception {
+                AccessibleComponent acmp = ac.getAccessibleComponent();
+                if (acmp != null) {
+                    Rectangle r = acmp.getBounds();
+                    if (r != null) {
+                        try {
+                            Point p = acmp.getLocationOnScreen();
+                            if (p != null) {
+                                r.x = p.x;
+                                r.y = p.y;
+                                return r;
+                            }
+                        } catch (Exception e) {
+                            return null;
+                        }
+                    }
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+    /**
+     * returns the AccessibleComponent x-coord from an AccessibleContext
+     */
+    private int getAccessibleXcoordFromContext(AccessibleContext ac) {
+        if (ac != null) {
+            Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
+            if (r != null) {
+                debugString(" - Returning Accessible x coord from Context: " + r.x);
+                return r.x;
+            }
+        } else {
+            debugString("getAccessibleXcoordFromContext ac = null");
+        }
+        return -1;
+    }
+
+    /**
+     * returns the AccessibleComponent y-coord from an AccessibleContext
+     */
+    private int getAccessibleYcoordFromContext(AccessibleContext ac) {
+        debugString("getAccessibleYcoordFromContext() called");
+        if (ac != null) {
+            Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
+            if (r != null) {
+                return r.y;
+            }
+        } else {
+        debugString("getAccessibleYcoordFromContext; ac = null");
+        }
+        return -1;
+    }
+
+    /**
+     * returns the AccessibleComponent height from an AccessibleContext
+     */
+    private int getAccessibleHeightFromContext(AccessibleContext ac) {
+        if (ac != null) {
+            Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
+            if (r != null) {
+                return r.height;
+            }
+        } else {
+            debugString("getAccessibleHeightFromContext; ac = null");
+        }
+        return -1;
+    }
+
+    /**
+     * returns the AccessibleComponent width from an AccessibleContext
+     */
+    private int getAccessibleWidthFromContext(AccessibleContext ac) {
+        if (ac != null) {
+            Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
+            if (r != null) {
+                return r.width;
+            }
+        } else {
+            debugString("getAccessibleWidthFromContext; ac = null");
+        }
+        return -1;
+    }
+
+
+    /**
+     * returns the AccessibleComponent from an AccessibleContext
+     */
+    private AccessibleComponent getAccessibleComponentFromContext(AccessibleContext ac) {
+        if (ac != null) {
+            AccessibleComponent acmp = ac.getAccessibleComponent();
+            if (acmp != null) {
+                debugString("Returning AccessibleComponent Context");
+                return acmp;
+            }
+        } else {
+            debugString("getAccessibleComponentFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * returns the AccessibleAction from an AccessibleContext
+     */
+    private AccessibleAction getAccessibleActionFromContext(final AccessibleContext ac) {
+        debugString("Returning AccessibleAction Context");
+        return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleAction>() {
+            @Override
+            public AccessibleAction call() throws Exception {
+                return ac.getAccessibleAction();
+            }
+        }, ac);
+    }
+
+    /**
+     * returns the AccessibleSelection from an AccessibleContext
+     */
+    private AccessibleSelection getAccessibleSelectionFromContext(final AccessibleContext ac) {
+        return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleSelection>() {
+            @Override
+            public AccessibleSelection call() throws Exception {
+                return ac.getAccessibleSelection();
+            }
+        }, ac);
+    }
+
+    /**
+     * return the AccessibleText from an AccessibleContext
+     */
+    private AccessibleText getAccessibleTextFromContext(final AccessibleContext ac) {
+        return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {
+            @Override
+            public AccessibleText call() throws Exception {
+                return ac.getAccessibleText();
+            }
+        }, ac);
+    }
+
+    /**
+     * return the AccessibleComponent from an AccessibleContext
+     */
+    private AccessibleValue getAccessibleValueFromContext(final AccessibleContext ac) {
+        return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {
+            @Override
+            public AccessibleValue call() throws Exception {
+                return ac.getAccessibleValue();
+            }
+        }, ac);
+    }
+
+    /* ===== AccessibleText methods ===== */
+
+    /**
+     * returns the bounding rectangle for the text cursor
+     * XXX
+     */
+    private Rectangle getCaretLocation(final AccessibleContext ac) {
+    debugString("getCaretLocation");
+        if (ac==null)
+            return null;
+        return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {
+            @Override
+            public Rectangle call() throws Exception {
+                // workaround for JAAPI not returning cursor bounding rectangle
+                Rectangle r = null;
+                Accessible parent = ac.getAccessibleParent();
+                if (parent instanceof Accessible) {
+                    int indexInParent = ac.getAccessibleIndexInParent();
+                    Accessible child =
+                            parent.getAccessibleContext().getAccessibleChild(indexInParent);
+
+                    if (child instanceof JTextComponent) {
+                        JTextComponent text = (JTextComponent) child;
+                        try {
+                            r = text.modelToView(text.getCaretPosition());
+                            if (r != null) {
+                                Point p = text.getLocationOnScreen();
+                                r.translate(p.x, p.y);
+                            }
+                        } catch (BadLocationException ble) {
+                        }
+                    }
+                }
+                return r;
+            }
+        }, ac);
+    }
+
+    /**
+     * returns the x-coordinate for the text cursor rectangle
+     */
+    private int getCaretLocationX(AccessibleContext ac) {
+        Rectangle r = getCaretLocation(ac);
+        if (r != null) {
+            return r.x;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * returns the y-coordinate for the text cursor rectangle
+     */
+    private int getCaretLocationY(AccessibleContext ac) {
+        Rectangle r = getCaretLocation(ac);
+        if (r != null) {
+            return r.y;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * returns the height for the text cursor rectangle
+     */
+    private int getCaretLocationHeight(AccessibleContext ac) {
+        Rectangle r = getCaretLocation(ac);
+        if (r != null) {
+            return r.height;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * returns the width for the text cursor rectangle
+     */
+    private int getCaretLocationWidth(AccessibleContext ac) {
+        Rectangle r = getCaretLocation(ac);
+        if (r != null) {
+            return r.width;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * returns the character count from an AccessibleContext
+     */
+    private int getAccessibleCharCountFromContext(final AccessibleContext ac) {
+        if (ac==null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (at != null) {
+                    return at.getCharCount();
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /**
+     * returns the caret position from an AccessibleContext
+     */
+    private int getAccessibleCaretPositionFromContext(final AccessibleContext ac) {
+        if (ac==null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (at != null) {
+                    return at.getCaretPosition();
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /**
+     * Return the index at a specific point from an AccessibleContext
+     * Point(x, y) is in screen coordinates.
+     */
+    private int getAccessibleIndexAtPointFromContext(final AccessibleContext ac,
+                                                    final int x, final int y) {
+        debugString("getAccessibleIndexAtPointFromContext: x = "+x+"; y = "+y);
+        if (ac==null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                AccessibleComponent acomp = ac.getAccessibleComponent();
+                if (at != null && acomp != null) {
+                    // Convert x and y from screen coordinates to
+                    // local coordinates.
+                    try {
+                        Point p = acomp.getLocationOnScreen();
+                        int x1, y1;
+                        if (p != null) {
+                            x1 = x - p.x;
+                            if (x1 < 0) {
+                                x1 = 0;
+                            }
+                            y1 = y - p.y;
+                            if (y1 < 0) {
+                                y1 = 0;
+                            }
+
+                            Point newPoint = new Point(x1, y1);
+                            int indexAtPoint = at.getIndexAtPoint(new Point(x1, y1));
+                            return indexAtPoint;
+                        }
+                    } catch (Exception e) {
+                    }
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /**
+     * return the letter at a specific point from an AccessibleContext
+     */
+    private String getAccessibleLetterAtIndexFromContext(final AccessibleContext ac, final int index) {
+        if (ac != null) {
+            String s = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    AccessibleText at = ac.getAccessibleText();
+                    if (at == null) return null;
+                    return at.getAtIndex(AccessibleText.CHARACTER, index);
+                }
+            }, ac);
+            if (s != null) {
+                references.increment(s);
+                return s;
+            }
+        } else {
+            debugString("getAccessibleLetterAtIndexFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the word at a specific point from an AccessibleContext
+     */
+    private String getAccessibleWordAtIndexFromContext(final AccessibleContext ac, final int index) {
+        if (ac != null) {
+            String s = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    AccessibleText at = ac.getAccessibleText();
+                    if (at == null) return null;
+                    return at.getAtIndex(AccessibleText.WORD, index);
+                }
+            }, ac);
+            if (s != null) {
+                references.increment(s);
+                return s;
+            }
+        } else {
+            debugString("getAccessibleWordAtIndexFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the sentence at a specific point from an AccessibleContext
+     */
+    private String getAccessibleSentenceAtIndexFromContext(final AccessibleContext ac, final int index) {
+        if (ac != null) {
+            String s = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    AccessibleText at = ac.getAccessibleText();
+                    if (at == null) return null;
+                    return at.getAtIndex(AccessibleText.SENTENCE, index);
+                }
+            }, ac);
+            if (s != null) {
+                references.increment(s);
+                return s;
+            }
+        } else {
+            debugString("getAccessibleSentenceAtIndexFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the text selection start from an AccessibleContext
+     */
+    private int getAccessibleTextSelectionStartFromContext(final AccessibleContext ac) {
+        if (ac == null) return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (at != null) {
+                    return at.getSelectionStart();
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /**
+     * return the text selection end from an AccessibleContext
+     */
+    private int getAccessibleTextSelectionEndFromContext(final AccessibleContext ac) {
+        if (ac == null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (at != null) {
+                    return at.getSelectionEnd();
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /**
+     * return the selected text from an AccessibleContext
+     */
+    private String getAccessibleTextSelectedTextFromContext(final AccessibleContext ac) {
+        if (ac != null) {
+            String s = InvocationUtils.invokeAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    AccessibleText at = ac.getAccessibleText();
+                    if (at == null) return null;
+                    return at.getSelectedText();
+                }
+            }, ac);
+            if (s != null) {
+                references.increment(s);
+                return s;
+            }
+        } else {
+            debugString("getAccessibleTextSelectedTextFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the attribute string at a given index from an AccessibleContext
+     */
+    private String getAccessibleAttributesAtIndexFromContext(final AccessibleContext ac,
+                                                             final int index) {
+        if (ac == null)
+            return null;
+        AttributeSet as = InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {
+            @Override
+            public AttributeSet call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (at != null) {
+                    return at.getCharacterAttribute(index);
+                }
+                return null;
+            }
+        }, ac);
+        String s = expandStyleConstants(as);
+        if (s != null) {
+            references.increment(s);
+            return s;
+        }
+        return null;
+    }
+
+    /**
+     * Get line info: left index of line
+     *
+     * algorithm:  cast back, doubling each time,
+     *             'till find line boundaries
+     *
+     * return -1 if we can't get the info (e.g. index or at passed in
+     * is bogus; etc.)
+     */
+    private int getAccessibleTextLineLeftBoundsFromContext(final AccessibleContext ac,
+                                                          final int index) {
+        if (ac == null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (at != null) {
+                    int lineStart;
+                    int offset;
+                    Rectangle charRect;
+                    Rectangle indexRect = at.getCharacterBounds(index);
+                    int textLen = at.getCharCount();
+                    if (indexRect == null) {
+                        return -1;
+                    }
+                    // find the start of the line
+                    //
+                    offset = 1;
+                    lineStart = index - offset < 0 ? 0 : index - offset;
+                    charRect = at.getCharacterBounds(lineStart);
+                    // slouch behind beginning of line
+                    while (charRect != null
+                            && charRect.y >= indexRect.y
+                            && lineStart > 0) {
+                        offset = offset << 1;
+                        lineStart = index - offset < 0 ? 0 : index - offset;
+                        charRect = at.getCharacterBounds(lineStart);
+                    }
+                    if (lineStart == 0) {    // special case: we're on the first line!
+                        // we found it!
+                    } else {
+                        offset = offset >> 1;   // know boundary within last expansion
+                        // ground forward to beginning of line
+                        while (offset > 0) {
+                            charRect = at.getCharacterBounds(lineStart + offset);
+                            if (charRect.y < indexRect.y) { // still before line
+                                lineStart += offset;
+                            } else {
+                                // leave lineStart alone, it's close!
+                            }
+                            offset = offset >> 1;
+                        }
+                        // subtract one 'cause we're already too far...
+                        lineStart += 1;
+                    }
+                    return lineStart;
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /**
+     * Get line info: right index of line
+     *
+     * algorithm:  cast back, doubling each time,
+     *             'till find line boundaries
+     *
+     * return -1 if we can't get the info (e.g. index or at passed in
+     * is bogus; etc.)
+     */
+    private int getAccessibleTextLineRightBoundsFromContext(final AccessibleContext ac, final int index) {
+        if(ac == null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (at != null) {
+                    int lineEnd;
+                    int offset;
+                    Rectangle charRect;
+                    Rectangle indexRect = at.getCharacterBounds(index);
+                    int textLen = at.getCharCount();
+                    if (indexRect == null) {
+                        return -1;
+                    }
+                    // find the end of the line
+                    //
+                    offset = 1;
+                    lineEnd = index + offset > textLen - 1
+                            ? textLen - 1 : index + offset;
+                    charRect = at.getCharacterBounds(lineEnd);
+                    // push past end of line
+                    while (charRect != null &&
+                            charRect.y <= indexRect.y &&
+                            lineEnd < textLen - 1) {
+                        offset = offset << 1;
+                        lineEnd = index + offset > textLen - 1
+                                ? textLen - 1 : index + offset;
+                        charRect = at.getCharacterBounds(lineEnd);
+                    }
+                    if (lineEnd == textLen - 1) {    // special case: on the last line!
+                        // we found it!
+                    } else {
+                        offset = offset >> 1;   // know boundary within last expansion
+                        // pull back to end of line
+                        while (offset > 0) {
+                            charRect = at.getCharacterBounds(lineEnd - offset);
+                            if (charRect.y > indexRect.y) { // still beyond line
+                                lineEnd -= offset;
+                            } else {
+                                // leave lineEnd alone, it's close!
+                            }
+                            offset = offset >> 1;
+                        }
+                        // subtract one 'cause we're already too far...
+                        lineEnd -= 1;
+                    }
+                    return lineEnd;
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /**
+     * Get a range of text; null if indicies are bogus
+     */
+    private String getAccessibleTextRangeFromContext(final AccessibleContext ac,
+                                                    final int start, final int end) {
+        String s = InvocationUtils.invokeAndWait(new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                if (ac != null) {
+                    AccessibleText at = ac.getAccessibleText();
+                    if (at != null) {
+                        // start - end is inclusive
+                        if (start > end) {
+                            return null;
+                        }
+                        if (end >= at.getCharCount()) {
+                            return null;
+                        }
+                        StringBuffer buf = new StringBuffer(end - start + 1);
+                        for (int i = start; i <= end; i++) {
+                            buf.append(at.getAtIndex(AccessibleText.CHARACTER, i));
+                        }
+                        return buf.toString();
+                    }
+                }
+                return null;
+            }
+        }, ac);
+        if (s != null) {
+            references.increment(s);
+            return s;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * return the AttributeSet object at a given index from an AccessibleContext
+     */
+    private AttributeSet getAccessibleAttributeSetAtIndexFromContext(final AccessibleContext ac,
+                                                                    final int index) {
+        return InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {
+            @Override
+            public AttributeSet call() throws Exception {
+                if (ac != null) {
+                    AccessibleText at = ac.getAccessibleText();
+                    if (at != null) {
+                        AttributeSet as = at.getCharacterAttribute(index);
+                        if (as != null) {
+                            AccessBridge.this.references.increment(as);
+                            return as;
+                        }
+                    }
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+
+    /**
+     * return the bounding rectangle at index from an AccessibleContext
+     */
+    private Rectangle getAccessibleTextRectAtIndexFromContext(final AccessibleContext ac,
+                                                        final int index) {
+        // want to do this in global coords, so need to combine w/ac global coords
+        Rectangle r = InvocationUtils.invokeAndWait(new Callable<Rectangle>() {
+            @Override
+            public Rectangle call() throws Exception {
+                // want to do this in global coords, so need to combine w/ac global coords
+                if (ac != null) {
+                    AccessibleText at = ac.getAccessibleText();
+                    if (at != null) {
+                        Rectangle rect = at.getCharacterBounds(index);
+                        if (rect != null) {
+                            String s = at.getAtIndex(AccessibleText.CHARACTER, index);
+                            if (s != null && s.equals("\n")) {
+                                rect.width = 0;
+                            }
+                            return rect;
+                        }
+                    }
+                }
+                return null;
+            }
+        }, ac);
+        Rectangle acRect = getAccessibleBoundsOnScreenFromContext(ac);
+        if (r != null && acRect != null) {
+            r.translate(acRect.x, acRect.y);
+            return r;
+        }
+        return null;
+    }
+
+    /**
+     * return the AccessibleText character x-coord at index from an AccessibleContext
+     */
+    private int getAccessibleXcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {
+        if (ac != null) {
+            Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
+            if (r != null) {
+                return r.x;
+            }
+        } else {
+            debugString("getAccessibleXcoordTextRectAtIndexFromContext; ac = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the AccessibleText character y-coord at index from an AccessibleContext
+     */
+    private int getAccessibleYcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {
+        if (ac != null) {
+            Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
+            if (r != null) {
+                return r.y;
+            }
+        } else {
+            debugString("getAccessibleYcoordTextRectAtIndexFromContext; ac = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the AccessibleText character height at index from an AccessibleContext
+     */
+    private int getAccessibleHeightTextRectAtIndexFromContext(AccessibleContext ac, int index) {
+        if (ac != null) {
+            Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
+            if (r != null) {
+                return r.height;
+            }
+        } else {
+            debugString("getAccessibleHeightTextRectAtIndexFromContext; ac = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the AccessibleText character width at index from an AccessibleContext
+     */
+    private int getAccessibleWidthTextRectAtIndexFromContext(AccessibleContext ac, int index) {
+        if (ac != null) {
+            Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
+            if (r != null) {
+                return r.width;
+            }
+        } else {
+            debugString("getAccessibleWidthTextRectAtIndexFromContext; ac = null");
+        }
+        return -1;
+    }
+
+    /* ===== AttributeSet methods for AccessibleText ===== */
+
+    /**
+     * return the bold setting from an AttributeSet
+     */
+    private boolean getBoldFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.isBold(as);
+        } else {
+            debugString("getBoldFromAttributeSet; as = null");
+        }
+        return false;
+    }
+
+    /**
+     * return the italic setting from an AttributeSet
+     */
+    private boolean getItalicFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.isItalic(as);
+        } else {
+            debugString("getItalicFromAttributeSet; as = null");
+        }
+        return false;
+    }
+
+    /**
+     * return the underline setting from an AttributeSet
+     */
+    private boolean getUnderlineFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.isUnderline(as);
+        } else {
+            debugString("getUnderlineFromAttributeSet; as = null");
+        }
+        return false;
+    }
+
+    /**
+     * return the strikethrough setting from an AttributeSet
+     */
+    private boolean getStrikethroughFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.isStrikeThrough(as);
+        } else {
+            debugString("getStrikethroughFromAttributeSet; as = null");
+        }
+        return false;
+    }
+
+    /**
+     * return the superscript setting from an AttributeSet
+     */
+    private boolean getSuperscriptFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.isSuperscript(as);
+        } else {
+            debugString("getSuperscriptFromAttributeSet; as = null");
+        }
+        return false;
+    }
+
+    /**
+     * return the subscript setting from an AttributeSet
+     */
+    private boolean getSubscriptFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.isSubscript(as);
+        } else {
+            debugString("getSubscriptFromAttributeSet; as = null");
+        }
+        return false;
+    }
+
+    /**
+     * return the background color from an AttributeSet
+     */
+    private String getBackgroundColorFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            String s = StyleConstants.getBackground(as).toString();
+            if (s != null) {
+                references.increment(s);
+                return s;
+            }
+        } else {
+            debugString("getBackgroundColorFromAttributeSet; as = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the foreground color from an AttributeSet
+     */
+    private String getForegroundColorFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            String s = StyleConstants.getForeground(as).toString();
+            if (s != null) {
+                references.increment(s);
+                return s;
+            }
+        } else {
+            debugString("getForegroundColorFromAttributeSet; as = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the font family from an AttributeSet
+     */
+    private String getFontFamilyFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            String s = StyleConstants.getFontFamily(as).toString();
+            if (s != null) {
+                references.increment(s);
+                return s;
+            }
+        } else {
+            debugString("getFontFamilyFromAttributeSet; as = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the font size from an AttributeSet
+     */
+    private int getFontSizeFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.getFontSize(as);
+        } else {
+            debugString("getFontSizeFromAttributeSet; as = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the alignment from an AttributeSet
+     */
+    private int getAlignmentFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.getAlignment(as);
+        } else {
+            debugString("getAlignmentFromAttributeSet; as = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the BiDi level from an AttributeSet
+     */
+    private int getBidiLevelFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.getBidiLevel(as);
+        } else {
+            debugString("getBidiLevelFromAttributeSet; as = null");
+        }
+        return -1;
+    }
+
+
+    /**
+     * return the first line indent from an AttributeSet
+     */
+    private float getFirstLineIndentFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.getFirstLineIndent(as);
+        } else {
+            debugString("getFirstLineIndentFromAttributeSet; as = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the left indent from an AttributeSet
+     */
+    private float getLeftIndentFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.getLeftIndent(as);
+        } else {
+            debugString("getLeftIndentFromAttributeSet; as = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the right indent from an AttributeSet
+     */
+    private float getRightIndentFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.getRightIndent(as);
+        } else {
+            debugString("getRightIndentFromAttributeSet; as = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the line spacing from an AttributeSet
+     */
+    private float getLineSpacingFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.getLineSpacing(as);
+        } else {
+            debugString("getLineSpacingFromAttributeSet; as = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the space above from an AttributeSet
+     */
+    private float getSpaceAboveFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.getSpaceAbove(as);
+        } else {
+            debugString("getSpaceAboveFromAttributeSet; as = null");
+        }
+        return -1;
+    }
+
+    /**
+     * return the space below from an AttributeSet
+     */
+    private float getSpaceBelowFromAttributeSet(AttributeSet as) {
+        if (as != null) {
+            return StyleConstants.getSpaceBelow(as);
+        } else {
+            debugString("getSpaceBelowFromAttributeSet; as = null");
+        }
+        return -1;
+    }
+
+    /**
+     * Enumerate all StyleConstants in the AttributeSet
+     *
+     * We need to check explicitly, 'cause of the HTML package conversion
+     * mechanism (they may not be stored as StyleConstants, just translated
+     * to them when asked).
+     *
+     * (Use convenience methods where they are defined...)
+     *
+     * Not checking the following (which the IBM SNS guidelines says
+     * should be defined):
+     *    - ComponentElementName
+     *    - IconElementName
+     *    - NameAttribute
+     *    - ResolveAttribute
+     */
+    private String expandStyleConstants(AttributeSet as) {
+        Color c;
+        Object o;
+        String attrString = "";
+
+        // ---------- check for various Character Constants
+
+        attrString += "BidiLevel = " + StyleConstants.getBidiLevel(as);
+
+        final Component comp = StyleConstants.getComponent(as);
+        if (comp != null) {
+            if (comp instanceof Accessible) {
+                final AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                    @Override
+                    public AccessibleContext call() throws Exception {
+                        return comp.getAccessibleContext();
+                    }
+                }, comp);
+                if (ac != null) {
+                    attrString += "; Accessible Component = " + InvocationUtils.invokeAndWait(new Callable<String>() {
+                        @Override
+                        public String call() throws Exception {
+                            return ac.getAccessibleName();
+                        }
+                    }, ac);
+                } else {
+                    attrString += "; Innaccessible Component = " + comp;
+                }
+            } else {
+                attrString += "; Innaccessible Component = " + comp;
+            }
+        }
+
+        Icon i = StyleConstants.getIcon(as);
+        if (i != null) {
+            if (i instanceof ImageIcon) {
+                attrString += "; ImageIcon = " + ((ImageIcon) i).getDescription();
+            } else {
+                attrString += "; Icon = " + i;
+            }
+        }
+
+        attrString += "; FontFamily = " + StyleConstants.getFontFamily(as);
+
+        attrString += "; FontSize = " + StyleConstants.getFontSize(as);
+
+        if (StyleConstants.isBold(as)) {
+            attrString += "; bold";
+        }
+
+        if (StyleConstants.isItalic(as)) {
+            attrString += "; italic";
+        }
+
+        if (StyleConstants.isUnderline(as)) {
+            attrString += "; underline";
+        }
+
+        if (StyleConstants.isStrikeThrough(as)) {
+            attrString += "; strikethrough";
+        }
+
+        if (StyleConstants.isSuperscript(as)) {
+            attrString += "; superscript";
+        }
+
+        if (StyleConstants.isSubscript(as)) {
+            attrString += "; subscript";
+        }
+
+        c = StyleConstants.getForeground(as);
+        if (c != null) {
+            attrString += "; Foreground = " + c;
+        }
+
+        c = StyleConstants.getBackground(as);
+        if (c != null) {
+            attrString += "; Background = " + c;
+        }
+
+        attrString += "; FirstLineIndent = " + StyleConstants.getFirstLineIndent(as);
+
+        attrString += "; RightIndent = " + StyleConstants.getRightIndent(as);
+
+        attrString += "; LeftIndent = " + StyleConstants.getLeftIndent(as);
+
+        attrString += "; LineSpacing = " + StyleConstants.getLineSpacing(as);
+
+        attrString += "; SpaceAbove = " + StyleConstants.getSpaceAbove(as);
+
+        attrString += "; SpaceBelow = " + StyleConstants.getSpaceBelow(as);
+
+        attrString += "; Alignment = " + StyleConstants.getAlignment(as);
+
+        TabSet ts = StyleConstants.getTabSet(as);
+        if (ts != null) {
+            attrString += "; TabSet = " + ts;
+        }
+
+        return attrString;
+    }
+
+
+    /* ===== AccessibleValue methods ===== */
+
+    /**
+     * return the AccessibleValue current value from an AccessibleContext
+     * returned using a String 'cause the value is a java Number
+     *
+     */
+    private String getCurrentAccessibleValueFromContext(final AccessibleContext ac) {
+        if (ac != null) {
+            final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
+                @Override
+                public Number call() throws Exception {
+                    AccessibleValue av = ac.getAccessibleValue();
+                    if (av == null) return null;
+                    return av.getCurrentAccessibleValue();
+                }
+            }, ac);
+            if (value != null) {
+                String s = value.toString();
+                if (s != null) {
+                    references.increment(s);
+                    return s;
+                }
+            }
+        } else {
+            debugString("getCurrentAccessibleValueFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the AccessibleValue maximum value from an AccessibleContext
+     * returned using a String 'cause the value is a java Number
+     *
+     */
+    private String getMaximumAccessibleValueFromContext(final AccessibleContext ac) {
+        if (ac != null) {
+            final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
+                @Override
+                public Number call() throws Exception {
+                    AccessibleValue av = ac.getAccessibleValue();
+                    if (av == null) return null;
+                    return av.getMaximumAccessibleValue();
+                }
+            }, ac);
+            if (value != null) {
+                String s = value.toString();
+                if (s != null) {
+                    references.increment(s);
+                    return s;
+                }
+            }
+        } else {
+            debugString("getMaximumAccessibleValueFromContext; ac = null");
+        }
+        return null;
+    }
+
+    /**
+     * return the AccessibleValue minimum value from an AccessibleContext
+     * returned using a String 'cause the value is a java Number
+     *
+     */
+    private String getMinimumAccessibleValueFromContext(final AccessibleContext ac) {
+        if (ac != null) {
+            final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
+                @Override
+                public Number call() throws Exception {
+                    AccessibleValue av = ac.getAccessibleValue();
+                    if (av == null) return null;
+                    return av.getMinimumAccessibleValue();
+                }
+            }, ac);
+            if (value != null) {
+                String s = value.toString();
+                if (s != null) {
+                    references.increment(s);
+                    return s;
+                }
+            }
+        } else {
+            debugString("getMinimumAccessibleValueFromContext; ac = null");
+        }
+        return null;
+    }
+
+
+    /* ===== AccessibleSelection methods ===== */
+
+    /**
+     * add to the AccessibleSelection of an AccessibleContext child i
+     *
+     */
+    private void addAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {
+        try {
+            InvocationUtils.invokeAndWait(new Callable<Object>() {
+                @Override
+                public Object call() throws Exception {
+                    if (ac != null) {
+                        AccessibleSelection as = ac.getAccessibleSelection();
+                        if (as != null) {
+                            as.addAccessibleSelection(i);
+                        }
+                    }
+                    return null;
+                }
+            }, ac);
+        } catch(Exception e){}
+    }
+
+    /**
+     * clear all of the AccessibleSelection of an AccessibleContex
+     *
+     */
+    private void clearAccessibleSelectionFromContext(final AccessibleContext ac) {
+        try {
+            InvocationUtils.invokeAndWait(new Callable<Object>() {
+                @Override
+                public Object call() throws Exception {
+                    AccessibleSelection as = ac.getAccessibleSelection();
+                    if (as != null) {
+                        as.clearAccessibleSelection();
+                    }
+                    return null;
+                }
+            }, ac);
+        } catch(Exception e){}
+
+    }
+
+    /**
+     * get the AccessibleContext of the i-th AccessibleSelection of an AccessibleContext
+     *
+     */
+    private AccessibleContext getAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                if (ac != null) {
+                    AccessibleSelection as = ac.getAccessibleSelection();
+                    if (as != null) {
+                        Accessible a = as.getAccessibleSelection(i);
+                        if (a == null)
+                            return null;
+                        else
+                            return a.getAccessibleContext();
+                    }
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+    /**
+     * get number of things selected in the AccessibleSelection of an AccessibleContext
+     *
+     */
+    private int getAccessibleSelectionCountFromContext(final AccessibleContext ac) {
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                if (ac != null) {
+                    AccessibleSelection as = ac.getAccessibleSelection();
+                    if (as != null) {
+                        return as.getAccessibleSelectionCount();
+                    }
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /**
+     * return true if the i-th child of the AccessibleSelection of an AccessibleContext is selected
+     *
+     */
+    private boolean isAccessibleChildSelectedFromContext(final AccessibleContext ac, final int i) {
+        return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                if (ac != null) {
+                    AccessibleSelection as = ac.getAccessibleSelection();
+                    if (as != null) {
+                        return as.isAccessibleChildSelected(i);
+                    }
+                }
+                return false;
+            }
+        }, ac);
+    }
+
+    /**
+     * remove the i-th child from the AccessibleSelection of an AccessibleContext
+     *
+     */
+    private void removeAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {
+        InvocationUtils.invokeAndWait(new Callable<Object>() {
+            @Override
+            public Object call() throws Exception {
+                if (ac != null) {
+                    AccessibleSelection as = ac.getAccessibleSelection();
+                    if (as != null) {
+                        as.removeAccessibleSelection(i);
+                    }
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+    /**
+     * select all (if possible) of the children of the AccessibleSelection of an AccessibleContext
+     *
+     */
+    private void selectAllAccessibleSelectionFromContext(final AccessibleContext ac) {
+            InvocationUtils.invokeAndWait(new Callable<Object>() {
+                @Override
+                public Object call() throws Exception {
+                    if (ac != null) {
+                        AccessibleSelection as = ac.getAccessibleSelection();
+                        if (as != null) {
+                            as.selectAllAccessibleSelection();
+                        }
+                    }
+                    return null;
+                }
+            }, ac);
+    }
+
+    // ======== AccessibleTable ========
+
+    ConcurrentHashMap<AccessibleTable,AccessibleContext> hashtab = new ConcurrentHashMap<>();
+
+    /**
+     * returns the AccessibleTable for an AccessibleContext
+     */
+    private AccessibleTable getAccessibleTableFromContext(final AccessibleContext ac) {
+        String version = getJavaVersionProperty();
+        if ((version != null && version.compareTo("1.3") >= 0)) {
+            return InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {
+                @Override
+                public AccessibleTable call() throws Exception {
+                    if (ac != null) {
+                        AccessibleTable at = ac.getAccessibleTable();
+                        if (at != null) {
+                            AccessBridge.this.hashtab.put(at, ac);
+                            return at;
+                        }
+                    }
+                    return null;
+                }
+            }, ac);
+        }
+        return null;
+    }
+
+
+    /*
+     * returns the AccessibleContext that contains an AccessibleTable
+     */
+    private AccessibleContext getContextFromAccessibleTable(AccessibleTable at) {
+        return hashtab.get(at);
+    }
+
+    /*
+     * returns the row count for an AccessibleTable
+     */
+    private int getAccessibleTableRowCount(final AccessibleContext ac) {
+        debugString("##### getAccessibleTableRowCount");
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                if (ac != null) {
+                    AccessibleTable at = ac.getAccessibleTable();
+                    if (at != null) {
+                        return at.getAccessibleRowCount();
+                    }
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /*
+     * returns the column count for an AccessibleTable
+     */
+    private int getAccessibleTableColumnCount(final AccessibleContext ac) {
+        debugString("##### getAccessibleTableColumnCount");
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                if (ac != null) {
+                    AccessibleTable at = ac.getAccessibleTable();
+                    if (at != null) {
+                        return at.getAccessibleColumnCount();
+                    }
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /*
+     * returns the AccessibleContext for an AccessibleTable cell
+     */
+    private AccessibleContext getAccessibleTableCellAccessibleContext(final AccessibleTable at,
+                                                                      final int row, final int column) {
+        debugString("getAccessibleTableCellAccessibleContext: at = "+at.getClass());
+        if (at == null) return null;
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                if (!(at instanceof AccessibleContext)) {
+                    Accessible a = at.getAccessibleAt(row, column);
+                    if (a != null) {
+                        return a.getAccessibleContext();
+                    }
+                } else {
+                    // work-around for AccessibleJTable.getCurrentAccessibleContext returning
+                    // wrong renderer component when cell contains more than one component
+                    AccessibleContext ac = (AccessibleContext) at;
+                    Accessible parent = ac.getAccessibleParent();
+                    if (parent != null) {
+                        int indexInParent = ac.getAccessibleIndexInParent();
+                        Accessible child =
+                                parent.getAccessibleContext().getAccessibleChild(indexInParent);
+                        if (child instanceof JTable) {
+                            JTable table = (JTable) child;
+
+                            TableCellRenderer renderer = table.getCellRenderer(row, column);
+                            if (renderer == null) {
+                                Class<?> columnClass = table.getColumnClass(column);
+                                renderer = table.getDefaultRenderer(columnClass);
+                            }
+                            Component component =
+                                    renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),
+                                            false, false, row, column);
+                            if (component instanceof Accessible) {
+                                return component.getAccessibleContext();
+                            }
+                        }
+                    }
+                }
+                return null;
+            }
+        }, getContextFromAccessibleTable(at));
+    }
+
+    /*
+     * returns the index of a cell at a given row and column in an AccessibleTable
+     */
+    private int getAccessibleTableCellIndex(final AccessibleTable at, int row, int column) {
+        debugString("##### getAccessibleTableCellIndex: at="+at);
+        if (at != null) {
+            int cellIndex = row *
+                InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                    @Override
+                    public Integer call() throws Exception {
+                        return at.getAccessibleColumnCount();
+                    }
+                }, getContextFromAccessibleTable(at)) +
+                column;
+            debugString("   ##### getAccessibleTableCellIndex="+cellIndex);
+            return cellIndex;
+        }
+        debugString(" ##### getAccessibleTableCellIndex FAILED");
+        return -1;
+    }
+
+    /*
+     * returns the row extent of a cell at a given row and column in an AccessibleTable
+     */
+    private int getAccessibleTableCellRowExtent(final AccessibleTable at, final int row, final int column) {
+        debugString("##### getAccessibleTableCellRowExtent");
+        if (at != null) {
+            int rowExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                                                              @Override
+                                                              public Integer call() throws Exception {
+                                                                  return at.getAccessibleRowExtentAt(row, column);
+                                                              }
+                                                          },
+                    getContextFromAccessibleTable(at));
+            debugString("   ##### getAccessibleTableCellRowExtent="+rowExtent);
+            return rowExtent;
+        }
+        debugString(" ##### getAccessibleTableCellRowExtent FAILED");
+        return -1;
+    }
+
+    /*
+     * returns the column extent of a cell at a given row and column in an AccessibleTable
+     */
+    private int getAccessibleTableCellColumnExtent(final AccessibleTable at, final int row, final int column) {
+        debugString("##### getAccessibleTableCellColumnExtent");
+        if (at != null) {
+            int columnExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                                                                 @Override
+                                                                 public Integer call() throws Exception {
+                                                                     return at.getAccessibleColumnExtentAt(row, column);
+                                                                 }
+                                                             },
+                    getContextFromAccessibleTable(at));
+            debugString("   ##### getAccessibleTableCellColumnExtent="+columnExtent);
+            return columnExtent;
+        }
+        debugString(" ##### getAccessibleTableCellColumnExtent FAILED");
+        return -1;
+    }
+
+    /*
+     * returns whether a cell is selected at a given row and column in an AccessibleTable
+     */
+    private boolean isAccessibleTableCellSelected(final AccessibleTable at, final int row,
+                         final int column) {
+        debugString("##### isAccessibleTableCellSelected: ["+row+"]["+column+"]");
+        if (at == null)
+            return false;
+        return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                boolean isSelected = false;
+                Accessible a = at.getAccessibleAt(row, column);
+                if (a != null) {
+                    AccessibleContext ac = a.getAccessibleContext();
+                    if (ac == null)
+                        return false;
+                    AccessibleStateSet as = ac.getAccessibleStateSet();
+                    if (as != null) {
+                        isSelected = as.contains(AccessibleState.SELECTED);
+                    }
+                }
+                return isSelected;
+            }
+        }, getContextFromAccessibleTable(at));
+    }
+
+    /*
+     * returns an AccessibleTable that represents the row header in an
+     * AccessibleTable
+     */
+    private AccessibleTable getAccessibleTableRowHeader(final AccessibleContext ac) {
+        debugString(" #####  getAccessibleTableRowHeader called");
+        AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {
+            @Override
+            public AccessibleTable call() throws Exception {
+                if (ac != null) {
+                    AccessibleTable at = ac.getAccessibleTable();
+                    if (at != null) {
+                        return at.getAccessibleRowHeader();
+                    }
+                }
+                return null;
+            }
+        }, ac);
+        if (at != null) {
+            hashtab.put(at, ac);
+        }
+        return at;
+    }
+
+    /*
+     * returns an AccessibleTable that represents the column header in an
+     * AccessibleTable
+     */
+    private AccessibleTable getAccessibleTableColumnHeader(final AccessibleContext ac) {
+    debugString("##### getAccessibleTableColumnHeader");
+        if (ac == null)
+            return null;
+        AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {
+            @Override
+            public AccessibleTable call() throws Exception {
+                // workaround for getAccessibleColumnHeader NPE
+                // when the table header is null
+                Accessible parent = ac.getAccessibleParent();
+                if (parent != null) {
+                    int indexInParent = ac.getAccessibleIndexInParent();
+                    Accessible child =
+                            parent.getAccessibleContext().getAccessibleChild(indexInParent);
+                    if (child instanceof JTable) {
+                        JTable table = (JTable) child;
+                        if (table.getTableHeader() == null) {
+                            return null;
+                        }
+                    }
+                }
+                AccessibleTable at = ac.getAccessibleTable();
+                if (at != null) {
+                    return at.getAccessibleColumnHeader();
+                }
+                return null;
+            }
+        }, ac);
+        if (at != null) {
+            hashtab.put(at, ac);
+        }
+        return at;
+    }
+
+    /*
+     * returns the number of row headers in an AccessibleTable that represents
+     * the row header in an AccessibleTable
+     */
+    private int getAccessibleTableRowHeaderRowCount(AccessibleContext ac) {
+
+    debugString(" #####  getAccessibleTableRowHeaderRowCount called");
+        if (ac != null) {
+            final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);
+            if (atRowHeader != null) {
+                return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                    @Override
+                    public Integer call() throws Exception {
+                        if (atRowHeader != null) {
+                            return atRowHeader.getAccessibleRowCount();
+                        }
+                        return -1;
+                    }
+                }, ac);
+            }
+        }
+        return -1;
+    }
+
+    /*
+     * returns the number of column headers in an AccessibleTable that represents
+     * the row header in an AccessibleTable
+     */
+    private int getAccessibleTableRowHeaderColumnCount(AccessibleContext ac) {
+        debugString(" #####  getAccessibleTableRowHeaderColumnCount called");
+        if (ac != null) {
+            final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);
+            if (atRowHeader != null) {
+                return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                    @Override
+                    public Integer call() throws Exception {
+                        if (atRowHeader != null) {
+                            return atRowHeader.getAccessibleColumnCount();
+                        }
+                        return -1;
+                    }
+                }, ac);
+            }
+        }
+        debugString(" ##### getAccessibleTableRowHeaderColumnCount FAILED");
+        return -1;
+    }
+
+    /*
+     * returns the number of row headers in an AccessibleTable that represents
+     * the column header in an AccessibleTable
+     */
+    private int getAccessibleTableColumnHeaderRowCount(AccessibleContext ac) {
+
+    debugString("##### getAccessibleTableColumnHeaderRowCount");
+        if (ac != null) {
+            final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);
+            if (atColumnHeader != null) {
+                return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                    @Override
+                    public Integer call() throws Exception {
+                        if (atColumnHeader != null) {
+                            return atColumnHeader.getAccessibleRowCount();
+                        }
+                        return -1;
+                    }
+                }, ac);
+            }
+        }
+        debugString(" ##### getAccessibleTableColumnHeaderRowCount FAILED");
+        return -1;
+    }
+
+    /*
+     * returns the number of column headers in an AccessibleTable that represents
+     * the column header in an AccessibleTable
+     */
+    private int getAccessibleTableColumnHeaderColumnCount(AccessibleContext ac) {
+
+    debugString("#####  getAccessibleTableColumnHeaderColumnCount");
+        if (ac != null) {
+            final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);
+            if (atColumnHeader != null) {
+                return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                    @Override
+                    public Integer call() throws Exception {
+                        if (atColumnHeader != null) {
+                            return atColumnHeader.getAccessibleColumnCount();
+                        }
+                        return -1;
+                    }
+                }, ac);
+            }
+        }
+        debugString(" ##### getAccessibleTableColumnHeaderColumnCount FAILED");
+        return -1;
+    }
+
+    /*
+     * returns the description of a row header in an AccessibleTable
+     */
+    private AccessibleContext getAccessibleTableRowDescription(final AccessibleTable table,
+                                                              final int row) {
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                if (table != null) {
+                    Accessible a = table.getAccessibleRowDescription(row);
+                    if (a != null) {
+                        return a.getAccessibleContext();
+                    }
+                }
+                return null;
+            }
+        }, getContextFromAccessibleTable(table));
+    }
+
+    /*
+     * returns the description of a column header in an AccessibleTable
+     */
+    private AccessibleContext getAccessibleTableColumnDescription(final AccessibleTable at,
+                                                                 final int column) {
+        if (at == null)
+            return null;
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                Accessible a = at.getAccessibleColumnDescription(column);
+                if (a != null) {
+                    return a.getAccessibleContext();
+                }
+                return null;
+            }
+        }, getContextFromAccessibleTable(at));
+    }
+
+    /*
+     * returns the number of rows selected in an AccessibleTable
+     */
+    private int getAccessibleTableRowSelectionCount(final AccessibleTable at) {
+        if (at != null) {
+            return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                @Override
+                public Integer call() throws Exception {
+                    int[] selections = at.getSelectedAccessibleRows();
+                    if (selections != null)
+                        return selections.length;
+                    else
+                        return -1;
+                }
+            }, getContextFromAccessibleTable(at));
+        }
+        return -1;
+    }
+
+    /*
+     * returns the row number of the i-th selected row in an AccessibleTable
+     */
+    private int getAccessibleTableRowSelections(final AccessibleTable at, final int i) {
+        if (at != null) {
+            return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                @Override
+                public Integer call() throws Exception {
+                    int[] selections = at.getSelectedAccessibleRows();
+                    if (selections.length > i) {
+                        return selections[i];
+                    }
+                    return -1;
+                }
+            }, getContextFromAccessibleTable(at));
+        }
+        return -1;
+    }
+
+    /*
+     * returns whether a row is selected in an AccessibleTable
+     */
+    private boolean isAccessibleTableRowSelected(final AccessibleTable at,
+                                                 final int row) {
+        if (at == null)
+            return false;
+        return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return at.isAccessibleRowSelected(row);
+            }
+         }, getContextFromAccessibleTable(at));
+    }
+
+    /*
+     * returns whether a column is selected in an AccessibleTable
+     */
+    private boolean isAccessibleTableColumnSelected(final AccessibleTable at,
+                                                   final int column) {
+        if (at == null)
+            return false;
+        return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return at.isAccessibleColumnSelected(column);
+            }
+         }, getContextFromAccessibleTable(at));
+    }
+
+    /*
+     * returns the number of columns selected in an AccessibleTable
+     */
+    private int getAccessibleTableColumnSelectionCount(final AccessibleTable at) {
+        if (at == null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                int[] selections = at.getSelectedAccessibleColumns();
+                if (selections != null)
+                    return selections.length;
+                else
+                    return -1;
+            }
+        }, getContextFromAccessibleTable(at));
+    }
+
+    /*
+     * returns the row number of the i-th selected row in an AccessibleTable
+     */
+    private int getAccessibleTableColumnSelections(final AccessibleTable at, final int i) {
+        if (at == null)
+            return -1;
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                int[] selections = at.getSelectedAccessibleColumns();
+                if (selections != null && selections.length > i) {
+                    return selections[i];
+                }
+                return -1;
+            }
+        }, getContextFromAccessibleTable(at));
+    }
+
+    /* ===== AccessibleExtendedTable (since 1.4) ===== */
+
+    /*
+     * returns the row number for a cell at a given index in an AccessibleTable
+     */
+    private int getAccessibleTableRow(final AccessibleTable at, int index) {
+        if (at == null)
+            return -1;
+        int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return at.getAccessibleColumnCount();
+            }
+        }, getContextFromAccessibleTable(at));
+        return index / colCount;
+    }
+
+    /*
+     * returns the column number for a cell at a given index in an AccessibleTable
+     */
+    private int getAccessibleTableColumn(final AccessibleTable at, int index) {
+        if (at == null)
+            return -1;
+        int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return at.getAccessibleColumnCount();
+            }
+        }, getContextFromAccessibleTable(at));
+        return index % colCount;
+    }
+
+    /*
+     * returns the index for a cell at a given row and column in an
+     * AccessibleTable
+     */
+    private int getAccessibleTableIndex(final AccessibleTable at, int row, int column) {
+        if (at == null)
+            return -1;
+        int colCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return at.getAccessibleColumnCount();
+            }
+         }, getContextFromAccessibleTable(at));
+        return row * colCount + column;
+    }
+
+    // ===== AccessibleRelationSet =====
+
+    /*
+     * returns the number of relations in the AccessibleContext's
+     * AccessibleRelationSet
+     */
+    private int getAccessibleRelationCount(final AccessibleContext ac) {
+        String version = getJavaVersionProperty();
+        if ((version != null && version.compareTo("1.3") >= 0)) {
+            if (ac != null) {
+                AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {
+                    @Override
+                    public AccessibleRelationSet call() throws Exception {
+                        return ac.getAccessibleRelationSet();
+                    }
+                }, ac);
+                if (ars != null)
+                    return ars.size();
+            }
+        }
+        return 0;
+    }
+
+    /*
+     * returns the ith relation key in the AccessibleContext's
+     * AccessibleRelationSet
+     */
+    private String getAccessibleRelationKey(final AccessibleContext ac, final int i) {
+        return InvocationUtils.invokeAndWait(new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                if (ac != null) {
+                    AccessibleRelationSet ars = ac.getAccessibleRelationSet();
+                    if (ars != null) {
+                        AccessibleRelation[] relations = ars.toArray();
+                        if (relations != null && i >= 0 && i < relations.length) {
+                            return relations[i].getKey();
+                        }
+                    }
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+    /*
+     * returns the number of targets in a relation in the AccessibleContext's
+     * AccessibleRelationSet
+     */
+    private int getAccessibleRelationTargetCount(final AccessibleContext ac, final int i) {
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                if (ac != null) {
+                    AccessibleRelationSet ars = ac.getAccessibleRelationSet();
+                    if (ars != null) {
+                        AccessibleRelation[] relations = ars.toArray();
+                        if (relations != null && i >= 0 && i < relations.length) {
+                            Object[] targets = relations[i].getTarget();
+                            return targets.length;
+                        }
+                    }
+                }
+                return -1;
+            }
+        }, ac);
+    }
+
+    /*
+     * returns the jth target in the ith relation in the AccessibleContext's
+     * AccessibleRelationSet
+     */
+    private AccessibleContext getAccessibleRelationTarget(final AccessibleContext ac,
+                                                         final int i, final int j) {
+        debugString("***** getAccessibleRelationTarget");
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                if (ac != null) {
+                    AccessibleRelationSet ars = ac.getAccessibleRelationSet();
+                    if (ars != null) {
+                        AccessibleRelation[] relations = ars.toArray();
+                        if (relations != null && i >= 0 && i < relations.length) {
+                            Object[] targets = relations[i].getTarget();
+                            if (targets != null && j >= 0 & j < targets.length) {
+                                Object o = targets[j];
+                                if (o instanceof Accessible) {
+                                    return ((Accessible) o).getAccessibleContext();
+                                }
+                            }
+                        }
+                    }
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+    // ========= AccessibleHypertext =========
+
+    private Map<AccessibleHypertext, AccessibleContext> hyperTextContextMap = new WeakHashMap<>();
+    private Map<AccessibleHyperlink, AccessibleContext> hyperLinkContextMap = new WeakHashMap<>();
+
+    /*
+     * Returns the AccessibleHypertext
+     */
+    private AccessibleHypertext getAccessibleHypertext(final AccessibleContext ac) {
+        debugString("getAccessibleHyperlink");
+        if (ac==null)
+            return null;
+        AccessibleHypertext hypertext = InvocationUtils.invokeAndWait(new Callable<AccessibleHypertext>() {
+            @Override
+            public AccessibleHypertext call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (!(at instanceof AccessibleHypertext)) {
+                    return null;
+                }
+                return ((AccessibleHypertext) at);
+            }
+        }, ac);
+        hyperTextContextMap.put(hypertext, ac);
+        return hypertext;
+    }
+
+    /*
+     * Returns the number of AccessibleHyperlinks
+     */
+    private int getAccessibleHyperlinkCount(AccessibleContext ac) {
+        debugString("getAccessibleHyperlinkCount");
+        if (ac == null) {
+            return 0;
+        }
+        final AccessibleHypertext hypertext = getAccessibleHypertext(ac);
+        if (hypertext == null) {
+            return 0;
+        }
+        //return hypertext.getLinkCount();
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return hypertext.getLinkCount();
+            }
+        }, ac);
+    }
+
+    /*
+     * Returns the hyperlink at the specified index
+     */
+    private AccessibleHyperlink getAccessibleHyperlink(final AccessibleHypertext hypertext, final int i) {
+        debugString("getAccessibleHyperlink");
+        if (hypertext == null) {
+            return null;
+        }
+        AccessibleContext ac = hyperTextContextMap.get(hypertext);
+        if ( i < 0 || i >=
+             InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                 @Override
+                 public Integer call() throws Exception {
+                     return hypertext.getLinkCount();
+                 }
+             }, ac) ) {
+            return null;
+        }
+        AccessibleHyperlink acLink = InvocationUtils.invokeAndWait(new Callable<AccessibleHyperlink>() {
+            @Override
+            public AccessibleHyperlink call() throws Exception {
+                AccessibleHyperlink link = hypertext.getLink(i);
+                if (link == null || (!link.isValid())) {
+                    return null;
+                }
+                return link;
+            }
+        }, ac);
+        hyperLinkContextMap.put(acLink, ac);
+        return acLink;
+    }
+
+    /*
+     * Returns the hyperlink object description
+     */
+    private String getAccessibleHyperlinkText(final AccessibleHyperlink link) {
+        debugString("getAccessibleHyperlinkText");
+        if (link == null) {
+            return null;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                Object o = link.getAccessibleActionDescription(0);
+                if (o != null) {
+                    return o.toString();
+                }
+                return null;
+            }
+        }, hyperLinkContextMap.get(link));
+    }
+
+    /*
+     * Returns the hyperlink URL
+     */
+    private String getAccessibleHyperlinkURL(final AccessibleHyperlink link) {
+        debugString("getAccessibleHyperlinkURL");
+        if (link == null) {
+            return null;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                Object o = link.getAccessibleActionObject(0);
+                if (o != null) {
+                    return o.toString();
+                } else {
+                    return null;
+                }
+            }
+        }, hyperLinkContextMap.get(link));
+    }
+
+    /*
+     * Returns the start index of the hyperlink text
+     */
+    private int getAccessibleHyperlinkStartIndex(final AccessibleHyperlink link) {
+        debugString("getAccessibleHyperlinkStartIndex");
+        if (link == null) {
+            return -1;
+        }
+        return  InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return link.getStartIndex();
+            }
+        }, hyperLinkContextMap.get(link));
+    }
+
+    /*
+     * Returns the end index of the hyperlink text
+     */
+    private int getAccessibleHyperlinkEndIndex(final AccessibleHyperlink link) {
+        debugString("getAccessibleHyperlinkEndIndex");
+        if (link == null) {
+            return -1;
+        }
+        return  InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return link.getEndIndex();
+            }
+        }, hyperLinkContextMap.get(link));
+    }
+
+    /*
+     * Returns the index into an array of hyperlinks that
+     * is associated with this character index, or -1 if there
+     * is no hyperlink associated with this index.
+     */
+    private int getAccessibleHypertextLinkIndex(final AccessibleHypertext hypertext, final int charIndex) {
+        debugString("getAccessibleHypertextLinkIndex: charIndex = "+charIndex);
+        if (hypertext == null) {
+            return -1;
+        }
+        int linkIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return hypertext.getLinkIndex(charIndex);
+            }
+        }, hyperTextContextMap.get(hypertext));
+        debugString("getAccessibleHypertextLinkIndex returning "+linkIndex);
+        return linkIndex;
+    }
+
+    /*
+     * Actives the hyperlink
+     */
+    private boolean activateAccessibleHyperlink(final AccessibleContext ac,
+                                                final AccessibleHyperlink link) {
+        //debugString("activateAccessibleHyperlink: link = "+link.getClass());
+        if (link == null) {
+            return false;
+        }
+        boolean retval = InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return link.doAccessibleAction(0);
+            }
+        }, ac);
+        debugString("activateAccessibleHyperlink: returning = "+retval);
+        return retval;
+    }
+
+
+    // ============ AccessibleKeyBinding =============
+
+    /*
+     * returns the component mnemonic
+     */
+    private KeyStroke getMnemonic(final AccessibleContext ac) {
+        if (ac == null)
+            return null;
+        return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {
+            @Override
+            public KeyStroke call() throws Exception {
+                AccessibleComponent comp = ac.getAccessibleComponent();
+                if (!(comp instanceof AccessibleExtendedComponent)) {
+                    return null;
+                }
+                AccessibleExtendedComponent aec = (AccessibleExtendedComponent) comp;
+                if (aec != null) {
+                    AccessibleKeyBinding akb = aec.getAccessibleKeyBinding();
+                    if (akb != null) {
+                        Object o = akb.getAccessibleKeyBinding(0);
+                        if (o instanceof KeyStroke) {
+                            return (KeyStroke) o;
+                        }
+                    }
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+    /*
+     * returns the JMenuItem accelerator
+     */
+    private KeyStroke getAccelerator(final AccessibleContext ac) {
+        // workaround for getAccessibleKeyBinding not returning the
+        // JMenuItem accelerator
+        if (ac == null)
+            return null;
+        return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {
+            @Override
+            public KeyStroke call() throws Exception {
+                Accessible parent = ac.getAccessibleParent();
+                if (parent instanceof Accessible) {
+                    int indexInParent = ac.getAccessibleIndexInParent();
+                    Accessible child =
+                            parent.getAccessibleContext().getAccessibleChild(indexInParent);
+                    if (child instanceof JMenuItem) {
+                        JMenuItem menuItem = (JMenuItem) child;
+                        if (menuItem == null)
+                            return null;
+                        KeyStroke keyStroke = menuItem.getAccelerator();
+                        return keyStroke;
+                    }
+                }
+                return null;
+            }
+        }, ac);
+    }
+
+    /*
+     * returns 1-24 to indicate which F key is being used for a shortcut or 0 otherwise
+     */
+    private int fKeyNumber(KeyStroke keyStroke) {
+        if (keyStroke == null)
+            return 0;
+        int fKey = 0;
+        String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());
+        if (keyText != null && (keyText.length() == 2 || keyText.length() == 3)) {
+            String prefix = keyText.substring(0, 1);
+            if (prefix.equals("F")) {
+                try {
+                    int suffix = Integer.parseInt(keyText.substring(1));
+                    if (suffix >= 1 && suffix <= 24) {
+                        fKey = suffix;
+                    }
+                } catch (Exception e) { // ignore NumberFormatException
+                }
+            }
+        }
+        return fKey;
+    }
+
+    /*
+     * returns one of several important control characters or 0 otherwise
+     */
+    private int controlCode(KeyStroke keyStroke) {
+        if (keyStroke == null)
+            return 0;
+        int code = keyStroke.getKeyCode();
+        switch (code) {
+            case KeyEvent.VK_BACK_SPACE:
+            case KeyEvent.VK_DELETE:
+            case KeyEvent.VK_DOWN:
+            case KeyEvent.VK_END:
+            case KeyEvent.VK_HOME:
+            case KeyEvent.VK_INSERT:
+            case KeyEvent.VK_KP_DOWN:
+            case KeyEvent.VK_KP_LEFT:
+            case KeyEvent.VK_KP_RIGHT:
+            case KeyEvent.VK_KP_UP:
+            case KeyEvent.VK_LEFT:
+            case KeyEvent.VK_PAGE_DOWN:
+            case KeyEvent.VK_PAGE_UP:
+            case KeyEvent.VK_RIGHT:
+            case KeyEvent.VK_UP:
+                break;
+            default:
+                code = 0;
+                break;
+        }
+        return code;
+    }
+
+    /*
+     * returns the KeyStoke character
+     */
+    private char getKeyChar(KeyStroke keyStroke) {
+        // If the shortcut is an FKey return 1-24
+        if (keyStroke == null)
+            return 0;
+        int fKey = fKeyNumber(keyStroke);
+        if (fKey != 0) {
+            // return 0x00000001 through 0x00000018
+            debugString("   Shortcut is: F" + fKey);
+            return (char)fKey;
+        }
+        // If the accelerator is a control character, return it
+        int keyCode = controlCode(keyStroke);
+        if (keyCode != 0) {
+            debugString("   Shortcut is control character: " + Integer.toHexString(keyCode));
+            return (char)keyCode;
+        }
+        String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());
+        debugString("   Shortcut is: " + keyText);
+        if (keyText != null || keyText.length() > 0) {
+            CharSequence seq = keyText.subSequence(0, 1);
+            if (seq != null || seq.length() > 0) {
+                return seq.charAt(0);
+            }
+        }
+        return 0;
+    }
+
+    /*
+     * returns the KeyStroke modifiers as an int
+     */
+    private int getModifiers(KeyStroke keyStroke) {
+        if (keyStroke == null)
+            return 0;
+        debugString("In AccessBridge.getModifiers");
+        // modifiers is a bit strip where bits 0-7 indicate a traditional modifier
+        // such as Ctrl/Alt/Shift, bit 8 indicates an F key shortcut, and bit 9 indicates
+        // a control code shortcut such as the delete key.
+
+        int modifiers = 0;
+        // Is the shortcut an FKey?
+        if (fKeyNumber(keyStroke) != 0) {
+            modifiers |= 1 << 8;
+        }
+        // Is the shortcut a control code?
+        if (controlCode(keyStroke) != 0) {
+            modifiers |= 1 << 9;
+        }
+        // The following is needed in order to handle translated modifiers.
+        // getKeyModifiersText doesn't work because for example in German Strg is
+        // returned for Ctrl.
+
+        // There can be more than one modifier, e.g. if the modifier is ctrl + shift + B
+        // the toString text is "shift ctrl pressed B". Need to parse through that.
+        StringTokenizer st = new StringTokenizer(keyStroke.toString());
+        while (st.hasMoreTokens()) {
+            String text = st.nextToken();
+            // Meta+Ctrl+Alt+Shift
+            // 0-3 are shift, ctrl, meta, alt
+            // 4-7 are for Solaris workstations (though not being used)
+            if (text.startsWith("met")) {
+                debugString("   found meta");
+                modifiers |= ActionEvent.META_MASK;
+            }
+            if (text.startsWith("ctr")) {
+                debugString("   found ctrl");
+                modifiers |= ActionEvent.CTRL_MASK;
+            }
+            if (text.startsWith("alt")) {
+                debugString("   found alt");
+                modifiers |= ActionEvent.ALT_MASK;
+            }
+            if (text.startsWith("shi")) {
+                debugString("   found shift");
+                modifiers |= ActionEvent.SHIFT_MASK;
+            }
+        }
+        debugString("   returning modifiers: 0x" + Integer.toHexString(modifiers));
+        return modifiers;
+    }
+
+    /*
+     * returns the number of key bindings associated with this context
+     */
+    private int getAccessibleKeyBindingsCount(AccessibleContext ac) {
+        if (ac == null  || (! runningOnJDK1_4) )
+            return 0;
+        int count = 0;
+
+        if (getMnemonic(ac) != null) {
+            count++;
+        }
+        if (getAccelerator(ac) != null) {
+            count++;
+        }
+        return count;
+    }
+
+    /*
+     * returns the key binding character at the specified index
+     */
+    private char getAccessibleKeyBindingChar(AccessibleContext ac, int index) {
+        if (ac == null  || (! runningOnJDK1_4) )
+            return 0;
+        if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic
+            KeyStroke keyStroke = getAccelerator(ac);
+            if (keyStroke != null) {
+                return getKeyChar(keyStroke);
+            }
+        }
+        if (index == 0) {   // mnemonic
+            KeyStroke keyStroke = getMnemonic(ac);
+            if (keyStroke != null) {
+                return getKeyChar(keyStroke);
+            }
+        } else if (index == 1) { // accelerator
+            KeyStroke keyStroke = getAccelerator(ac);
+            if (keyStroke != null) {
+                return getKeyChar(keyStroke);
+            }
+        }
+        return 0;
+    }
+
+    /*
+     * returns the key binding modifiers at the specified index
+     */
+    private int getAccessibleKeyBindingModifiers(AccessibleContext ac, int index) {
+        if (ac == null  || (! runningOnJDK1_4) )
+            return 0;
+        if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic
+            KeyStroke keyStroke = getAccelerator(ac);
+            if (keyStroke != null) {
+                return getModifiers(keyStroke);
+            }
+        }
+        if (index == 0) {   // mnemonic
+            KeyStroke keyStroke = getMnemonic(ac);
+            if (keyStroke != null) {
+                return getModifiers(keyStroke);
+            }
+        } else if (index == 1) { // accelerator
+            KeyStroke keyStroke = getAccelerator(ac);
+            if (keyStroke != null) {
+                return getModifiers(keyStroke);
+            }
+        }
+        return 0;
+    }
+
+    // ========== AccessibleIcon ============
+
+    /*
+     * return the number of icons associated with this context
+     */
+    private int getAccessibleIconsCount(final AccessibleContext ac) {
+        debugString("getAccessibleIconsCount");
+        if (ac == null) {
+            return 0;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleIcon[] ai = ac.getAccessibleIcon();
+                if (ai == null) {
+                    return 0;
+                }
+                return ai.length;
+            }
+        }, ac);
+    }
+
+    /*
+     * return icon description at the specified index
+     */
+    private String getAccessibleIconDescription(final AccessibleContext ac, final int index) {
+        debugString("getAccessibleIconDescription: index = "+index);
+        if (ac == null) {
+            return null;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                AccessibleIcon[] ai = ac.getAccessibleIcon();
+                if (ai == null || index < 0 || index >= ai.length) {
+                    return null;
+                }
+                return ai[index].getAccessibleIconDescription();
+            }
+        }, ac);
+    }
+
+    /*
+     * return icon height at the specified index
+     */
+    private int getAccessibleIconHeight(final AccessibleContext ac, final int index) {
+        debugString("getAccessibleIconHeight: index = "+index);
+        if (ac == null) {
+            return 0;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleIcon[] ai = ac.getAccessibleIcon();
+                if (ai == null || index < 0 || index >= ai.length) {
+                    return 0;
+                }
+                return ai[index].getAccessibleIconHeight();
+            }
+        }, ac);
+    }
+
+    /*
+     * return icon width at the specified index
+     */
+    private int getAccessibleIconWidth(final AccessibleContext ac, final int index) {
+        debugString("getAccessibleIconWidth: index = "+index);
+        if (ac == null) {
+            return 0;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleIcon[] ai = ac.getAccessibleIcon();
+                if (ai == null || index < 0 || index >= ai.length) {
+                    return 0;
+                }
+                return ai[index].getAccessibleIconWidth();
+            }
+        }, ac);
+    }
+
+    // ========= AccessibleAction ===========
+
+    /*
+     * return the number of icons associated with this context
+     */
+    private int getAccessibleActionsCount(final AccessibleContext ac) {
+        debugString("getAccessibleActionsCount");
+        if (ac == null) {
+            return 0;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                AccessibleAction aa = ac.getAccessibleAction();
+                if (aa == null)
+                    return 0;
+                return aa.getAccessibleActionCount();
+            }
+        }, ac);
+    }
+
+    /*
+     * return icon description at the specified index
+     */
+    private String getAccessibleActionName(final AccessibleContext ac, final int index) {
+        debugString("getAccessibleActionName: index = "+index);
+        if (ac == null) {
+            return null;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                AccessibleAction aa = ac.getAccessibleAction();
+                if (aa == null) {
+                    return null;
+                }
+                return aa.getAccessibleActionDescription(index);
+            }
+        }, ac);
+    }
+    /*
+     * return icon description at the specified index
+     */
+    private boolean doAccessibleActions(final AccessibleContext ac, final String name) {
+        debugString("doAccessibleActions: action name = "+name);
+        if (ac == null || name == null) {
+            return false;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                AccessibleAction aa = ac.getAccessibleAction();
+                if (aa == null) {
+                    return false;
+                }
+                int index = -1;
+                int numActions = aa.getAccessibleActionCount();
+                for (int i = 0; i < numActions; i++) {
+                    String actionName = aa.getAccessibleActionDescription(i);
+                    if (name.equals(actionName)) {
+                        index = i;
+                        break;
+                    }
+                }
+                if (index == -1) {
+                    return false;
+                }
+                boolean retval = aa.doAccessibleAction(index);
+                return retval;
+            }
+        }, ac);
+    }
+
+    /* ===== AT utility methods ===== */
+
+    /**
+     * Sets the contents of an AccessibleContext that
+     * implements AccessibleEditableText with the
+     * specified text string.
+     * Returns whether successful.
+     */
+    private boolean setTextContents(final AccessibleContext ac, final String text) {
+        debugString("setTextContents: ac = "+ac+"; text = "+text);
+
+        if (! (ac instanceof AccessibleEditableText)) {
+            debugString("   ac not instanceof AccessibleEditableText: "+ac);
+            return false;
+        }
+        if (text == null) {
+            debugString("   text is null");
+            return false;
+        }
+
+        return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                // check whether the text field is editable
+                AccessibleStateSet ass = ac.getAccessibleStateSet();
+                if (!ass.contains(AccessibleState.ENABLED)) {
+                    return false;
+                }
+                ((AccessibleEditableText) ac).setTextContents(text);
+                return true;
+            }
+        }, ac);
+    }
+
+    /**
+     * Returns the Accessible Context of an Internal Frame object that is
+     * the ancestor of a given object.  If the object is an Internal Frame
+     * object or an Internal Frame ancestor object was found, returns the
+     * object's AccessibleContext.
+     * If there is no ancestor object that has an Accessible Role of
+     * Internal Frame, returns (AccessibleContext)0.
+     */
+    private AccessibleContext getInternalFrame (AccessibleContext ac) {
+        return getParentWithRole(ac, AccessibleRole.INTERNAL_FRAME.toString());
+    }
+
+    /**
+     * Returns the Accessible Context for the top level object in
+     * a Java Window.  This is same Accessible Context that is obtained
+     * from GetAccessibleContextFromHWND for that window.  Returns
+     * (AccessibleContext)0 on error.
+     */
+    private AccessibleContext getTopLevelObject (final AccessibleContext ac) {
+        debugString("getTopLevelObject; ac = "+ac);
+        if (ac == null) {
+            return null;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                if (ac.getAccessibleRole() == AccessibleRole.DIALOG) {
+                    // return the dialog, not the parent window
+                    return ac;
+                }
+
+                Accessible parent = ac.getAccessibleParent();
+                if (parent == null) {
+                    return ac;
+                }
+                Accessible tmp = parent;
+                while (tmp != null && tmp.getAccessibleContext() != null) {
+                    AccessibleContext ac2 = tmp.getAccessibleContext();
+                    if (ac2 != null && ac2.getAccessibleRole() == AccessibleRole.DIALOG) {
+                        // return the dialog, not the parent window
+                        return ac2;
+                    }
+                    parent = tmp;
+                    tmp = parent.getAccessibleContext().getAccessibleParent();
+                }
+                return parent.getAccessibleContext();
+            }
+        }, ac);
+    }
+
+    /**
+     * Returns the parent AccessibleContext that has the specified AccessibleRole.
+     * Returns null on error or if the AccessibleContext does not exist.
+     */
+    private AccessibleContext getParentWithRole (final AccessibleContext ac,
+                                                 final String roleName) {
+        debugString("getParentWithRole; ac = "+ac);
+        debugString("role = "+roleName);
+        if (ac == null || roleName == null) {
+            return null;
+        }
+
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                AccessibleRole role = AccessBridge.this.accessibleRoleMap.get(roleName);
+                if (role == null) {
+                    return ac;
+                }
+
+                Accessible parent = ac.getAccessibleParent();
+                if (parent == null && ac.getAccessibleRole() == role) {
+                    return ac;
+                }
+
+                Accessible tmp = parent;
+                AccessibleContext tmp_ac = null;
+
+                while (tmp != null && (tmp_ac = tmp.getAccessibleContext()) != null) {
+                    AccessibleRole ar = tmp_ac.getAccessibleRole();
+                    if (ar == role) {
+                        // found
+                        return tmp_ac;
+                    }
+                    parent = tmp;
+                    tmp = parent.getAccessibleContext().getAccessibleParent();
+                }
+                // not found
+                return null;
+            }
+        }, ac);
+    }
+
+    /**
+     * Returns the parent AccessibleContext that has the specified AccessibleRole.
+     * Otherwise, returns the top level object for the Java Window.
+     * Returns (AccessibleContext)0 on error.
+     */
+    private AccessibleContext getParentWithRoleElseRoot (AccessibleContext ac,
+                                                         String roleName) {
+        AccessibleContext retval = getParentWithRole(ac, roleName);
+        if (retval == null) {
+            retval = getTopLevelObject(ac);
+        }
+        return retval;
+    }
+
+    /**
+     * Returns how deep in the object hierarchy a given object is.
+     * The top most object in the object hierarchy has an object depth of 0.
+     * Returns -1 on error.
+     */
+    private int getObjectDepth(final AccessibleContext ac) {
+        debugString("getObjectDepth: ac = "+ac);
+
+        if (ac == null) {
+            return -1;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                int count = 0;
+                Accessible parent = ac.getAccessibleParent();
+                if (parent == null) {
+                    return count;
+                }
+                Accessible tmp = parent;
+                while (tmp != null && tmp.getAccessibleContext() != null) {
+                    parent = tmp;
+                    tmp = parent.getAccessibleContext().getAccessibleParent();
+                    count++;
+                }
+                return count;
+            }
+        }, ac);
+    }
+
+    /**
+     * Returns the Accessible Context of the current ActiveDescendent of an object.
+     * Returns (AccessibleContext)0 on error.
+     */
+    private AccessibleContext getActiveDescendent (final AccessibleContext ac) {
+        debugString("getActiveDescendent: ac = "+ac);
+        if (ac == null) {
+            return null;
+        }
+        // workaround for JTree bug where the only possible active
+        // descendent is the JTree root
+        final Accessible parent = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
+            @Override
+            public Accessible call() throws Exception {
+                return ac.getAccessibleParent();
+            }
+        }, ac);
+
+        if (parent != null) {
+            Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
+                @Override
+                public Accessible call() throws Exception {
+                    int indexInParent = ac.getAccessibleIndexInParent();
+                    return parent.getAccessibleContext().getAccessibleChild(indexInParent);
+                }
+            }, ac);
+
+            if (child instanceof JTree) {
+                // return the selected node
+                final JTree tree = (JTree)child;
+                return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                    @Override
+                    public AccessibleContext call() throws Exception {
+                        return new AccessibleJTreeNode(tree,
+                                tree.getSelectionPath(),
+                                null);
+                    }
+                }, child);
+            }
+        }
+
+        return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+            @Override
+            public AccessibleContext call() throws Exception {
+                AccessibleSelection as = ac.getAccessibleSelection();
+                if (as == null) {
+                    return null;
+                }
+                // assume single selection
+                if (as.getAccessibleSelectionCount() != 1) {
+                    return null;
+                }
+                Accessible a = as.getAccessibleSelection(0);
+                if (a == null) {
+                    return null;
+                }
+                return a.getAccessibleContext();
+            }
+        }, ac);
+    }
+
+
+    /**
+     * Additional methods for Teton
+     */
+
+    /**
+     * Gets the AccessibleName for a component based upon the JAWS algorithm.
+     * Returns whether successful.
+     *
+     * Bug ID 4916682 - Implement JAWS AccessibleName policy
+     */
+    private String getJAWSAccessibleName(final AccessibleContext ac) {
+        debugString("getJAWSAccessibleName");
+        if (ac == null) {
+            return null;
+        }
+        // placeholder
+        return InvocationUtils.invokeAndWait(new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                return ac.getAccessibleName();
+            }
+        }, ac);
+    }
+
+    /**
+     * Request focus for a component. Returns whether successful;
+     *
+     * Bug ID 4944757 - requestFocus method needed
+     */
+    private boolean requestFocus(final AccessibleContext ac) {
+        debugString("requestFocus");
+        if (ac == null) {
+            return false;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                AccessibleComponent acomp = ac.getAccessibleComponent();
+                if (acomp == null) {
+                    return false;
+                }
+                acomp.requestFocus();
+                return ac.getAccessibleStateSet().contains(AccessibleState.FOCUSED);
+            }
+        }, ac);
+    }
+
+    /**
+     * Selects text between two indices.  Selection includes the
+     * text at the start index and the text at the end index. Returns
+     * whether successful;
+     *
+     * Bug ID 4944758 - selectTextRange method needed
+     */
+    private boolean selectTextRange(final AccessibleContext ac, final int startIndex, final int endIndex) {
+        debugString("selectTextRange: start = "+startIndex+"; end = "+endIndex);
+        if (ac == null) {
+            return false;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (!(at instanceof AccessibleEditableText)) {
+                    return false;
+                }
+                ((AccessibleEditableText) at).selectText(startIndex, endIndex);
+
+                boolean result = at.getSelectionStart() == startIndex &&
+                        at.getSelectionEnd() == endIndex;
+                return result;
+            }
+        }, ac);
+    }
+
+    /**
+     * Set the caret to a text position. Returns whether successful;
+     *
+     * Bug ID 4944770 - setCaretPosition method needed
+     */
+    private boolean setCaretPosition(final AccessibleContext ac, final int position) {
+        debugString("setCaretPosition: position = "+position);
+        if (ac == null) {
+            return false;
+        }
+        return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                AccessibleText at = ac.getAccessibleText();
+                if (!(at instanceof AccessibleEditableText)) {
+                    return false;
+                }
+                ((AccessibleEditableText) at).selectText(position, position);
+                return at.getCaretPosition() == position;
+            }
+        }, ac);
+    }
+
+    /**
+     * Gets the number of visible children of an AccessibleContext.
+     *
+     * Bug ID 4944762- getVisibleChildren for list-like components needed
+     */
+    private int _visibleChildrenCount;
+    private AccessibleContext _visibleChild;
+    private int _currentVisibleIndex;
+    private boolean _foundVisibleChild;
+
+    private int getVisibleChildrenCount(AccessibleContext ac) {
+        debugString("getVisibleChildrenCount");
+        if (ac == null) {
+            return -1;
+        }
+        _visibleChildrenCount = 0;
+        _getVisibleChildrenCount(ac);
+        debugString("  _visibleChildrenCount = "+_visibleChildrenCount);
+        return _visibleChildrenCount;
+    }
+
+    /*
+     * Recursively descends AccessibleContext and gets the number
+     * of visible children
+     */
+    private void _getVisibleChildrenCount(final AccessibleContext ac) {
+        if (ac == null)
+            return;
+        int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return ac.getAccessibleChildrenCount();
+            }
+        }, ac);
+        for (int i = 0; i < numChildren; i++) {
+            final int idx = i;
+            final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                @Override
+                public AccessibleContext call() throws Exception {
+                    Accessible a = ac.getAccessibleChild(idx);
+                    if (a != null)
+                        return a.getAccessibleContext();
+                    else
+                        return null;
+                }
+            }, ac);
+            if ( ac2 == null ||
+                 (!InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+                     @Override
+                     public Boolean call() throws Exception {
+                         return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);
+                     }
+                 }, ac))
+               ) {
+                continue;
+            }
+            _visibleChildrenCount++;
+
+            if (InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                @Override
+                public Integer call() throws Exception {
+                    return ac2.getAccessibleChildrenCount();
+                }
+            }, ac) > 0 ) {
+                _getVisibleChildrenCount(ac2);
+            }
+        }
+    }
+
+    /**
+     * Gets the visible child of an AccessibleContext at the
+     * specified index
+     *
+     * Bug ID 4944762- getVisibleChildren for list-like components needed
+     */
+    private AccessibleContext getVisibleChild(AccessibleContext ac, int index) {
+        debugString("getVisibleChild: index = "+index);
+        if (ac == null) {
+            return null;
+        }
+        _visibleChild = null;
+        _currentVisibleIndex = 0;
+        _foundVisibleChild = false;
+        _getVisibleChild(ac, index);
+
+        if (_visibleChild != null) {
+            debugString( "    getVisibleChild: found child = " +
+                         InvocationUtils.invokeAndWait(new Callable<String>() {
+                             @Override
+                             public String call() throws Exception {
+                                 return AccessBridge.this._visibleChild.getAccessibleName();
+                             }
+                         }, ac) );
+        }
+        return _visibleChild;
+    }
+
+    /*
+     * Recursively searchs AccessibleContext and finds the visible component
+     * at the specified index
+     */
+    private void _getVisibleChild(final AccessibleContext ac, final int index) {
+        if (_visibleChild != null) {
+            return;
+        }
+
+        int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return ac.getAccessibleChildrenCount();
+            }
+        }, ac);
+        for (int i = 0; i < numChildren; i++) {
+            final int idx=i;
+            final AccessibleContext ac2=InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
+                @Override
+                public AccessibleContext call() throws Exception {
+                    Accessible a = ac.getAccessibleChild(idx);
+                    if (a == null)
+                        return null;
+                    else
+                        return a.getAccessibleContext();
+                }
+            }, ac);
+            if (ac2 == null ||
+            (!InvocationUtils.invokeAndWait(new Callable<Boolean>() {
+                @Override
+                public Boolean call() throws Exception {
+                    return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);
+                }
+            }, ac))) {
+                continue;
+            }
+            if (!_foundVisibleChild && _currentVisibleIndex == index) {
+            _visibleChild = ac2;
+            _foundVisibleChild = true;
+            return;
+            }
+            _currentVisibleIndex++;
+
+            if ( InvocationUtils.invokeAndWait(new Callable<Integer>() {
+                @Override
+                public Integer call() throws Exception {
+                    return ac2.getAccessibleChildrenCount();
+                }
+            }, ac) > 0 ) {
+                _getVisibleChild(ac2, index);
+            }
+        }
+    }
+
+
+    /* ===== Java object memory management code ===== */
+
+    /**
+     * Class to track object references to ensure the
+     * Java VM doesn't garbage collect them
+     */
+    private class ObjectReferences {
+
+        private class Reference {
+            private int value;
+
+            Reference(int i) {
+                value = i;
+            }
+
+            public String toString() {
+                return ("refCount: " + value);
+            }
+        }
+
+        /**
+        * table object references, to keep 'em from being garbage collected
+        */
+        private ConcurrentHashMap<Object,Reference> refs;
+
+        /**
+        * Constructor
+        */
+        ObjectReferences() {
+            refs = new ConcurrentHashMap<>(4);
+        }
+
+        /**
+        * Debugging: dump the contents of ObjectReferences' refs Hashtable
+        */
+        String dump() {
+            return refs.toString();
+        }
+
+        /**
+        * Increment ref count; set to 1 if we have no references for it
+        */
+        void increment(Object o) {
+            if (o == null){
+                debugString("ObjectReferences::increment - Passed in object is null");
+                return;
+            }
+
+            if (refs.containsKey(o)) {
+                (refs.get(o)).value++;
+            } else {
+                refs.put(o, new Reference(1));
+            }
+        }
+
+        /**
+        * Decrement ref count; remove if count drops to 0
+        */
+        void decrement(Object o) {
+            Reference aRef = refs.get(o);
+            if (aRef != null) {
+                aRef.value--;
+                if (aRef.value == 0) {
+                    refs.remove(o);
+                } else if (aRef.value < 0) {
+                    debugString("ERROR: decrementing reference count below 0");
+                }
+            } else {
+                debugString("ERROR: object to decrement not in ObjectReferences table");
+            }
+        }
+
+    }
+
+    /* ===== event handling code ===== */
+
+   /**
+     * native method for handling property change events
+     */
+    private native void propertyCaretChange(PropertyChangeEvent e,
+                        AccessibleContext src,
+                        int oldValue, int newValue);
+    private native void propertyDescriptionChange(PropertyChangeEvent e,
+                        AccessibleContext src,
+                        String oldValue, String newValue);
+    private native void propertyNameChange(PropertyChangeEvent e,
+                        AccessibleContext src,
+                        String oldValue, String newValue);
+    private native void propertySelectionChange(PropertyChangeEvent e,
+                        AccessibleContext src);
+    private native void propertyStateChange(PropertyChangeEvent e,
+                        AccessibleContext src,
+                        String oldValue, String newValue);
+    private native void propertyTextChange(PropertyChangeEvent e,
+                        AccessibleContext src);
+    private native void propertyValueChange(PropertyChangeEvent e,
+                        AccessibleContext src,
+                        String oldValue, String newValue);
+    private native void propertyVisibleDataChange(PropertyChangeEvent e,
+                        AccessibleContext src);
+    private native void propertyChildChange(PropertyChangeEvent e,
+                        AccessibleContext src,
+                        AccessibleContext oldValue,
+                        AccessibleContext newValue);
+    private native void propertyActiveDescendentChange(PropertyChangeEvent e,
+                        AccessibleContext src,
+                        AccessibleContext oldValue,
+                        AccessibleContext newValue);
+
+    private native void javaShutdown();
+
+    /**
+     * native methods for handling focus events
+     */
+    private native void focusGained(FocusEvent e, AccessibleContext src);
+    private native void focusLost(FocusEvent e, AccessibleContext src);
+
+    /**
+     * native method for handling caret events
+     */
+    private native void caretUpdate(CaretEvent e, AccessibleContext src);
+
+    /**
+     * native methods for handling mouse events
+     */
+    private native void mouseClicked(MouseEvent e, AccessibleContext src);
+    private native void mouseEntered(MouseEvent e, AccessibleContext src);
+    private native void mouseExited(MouseEvent e, AccessibleContext src);
+    private native void mousePressed(MouseEvent e, AccessibleContext src);
+    private native void mouseReleased(MouseEvent e, AccessibleContext src);
+
+    /**
+     * native methods for handling menu & popupMenu events
+     */
+    private native void menuCanceled(MenuEvent e, AccessibleContext src);
+    private native void menuDeselected(MenuEvent e, AccessibleContext src);
+    private native void menuSelected(MenuEvent e, AccessibleContext src);
+    private native void popupMenuCanceled(PopupMenuEvent e, AccessibleContext src);
+    private native void popupMenuWillBecomeInvisible(PopupMenuEvent e,
+                                                     AccessibleContext src);
+    private native void popupMenuWillBecomeVisible(PopupMenuEvent e,
+                                                   AccessibleContext src);
+
+    /* ===== event definitions ===== */
+
+    private static final long PROPERTY_CHANGE_EVENTS = 1;
+    private static final long FOCUS_GAINED_EVENTS = 2;
+    private static final long FOCUS_LOST_EVENTS = 4;
+    private static final long FOCUS_EVENTS = (FOCUS_GAINED_EVENTS | FOCUS_LOST_EVENTS);
+
+    private static final long CARET_UPATE_EVENTS = 8;
+    private static final long CARET_EVENTS = CARET_UPATE_EVENTS;
+
+    private static final long MOUSE_CLICKED_EVENTS = 16;
+    private static final long MOUSE_ENTERED_EVENTS = 32;
+    private static final long MOUSE_EXITED_EVENTS = 64;
+    private static final long MOUSE_PRESSED_EVENTS = 128;
+    private static final long MOUSE_RELEASED_EVENTS = 256;
+    private static final long MOUSE_EVENTS = (MOUSE_CLICKED_EVENTS | MOUSE_ENTERED_EVENTS |
+                                             MOUSE_EXITED_EVENTS | MOUSE_PRESSED_EVENTS |
+                                             MOUSE_RELEASED_EVENTS);
+
+    private static final long MENU_CANCELED_EVENTS = 512;
+    private static final long MENU_DESELECTED_EVENTS = 1024;
+    private static final long MENU_SELECTED_EVENTS = 2048;
+    private static final long MENU_EVENTS = (MENU_CANCELED_EVENTS | MENU_DESELECTED_EVENTS |
+                                            MENU_SELECTED_EVENTS);
+
+    private static final long POPUPMENU_CANCELED_EVENTS = 4096;
+    private static final long POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS = 8192;
+    private static final long POPUPMENU_WILL_BECOME_VISIBLE_EVENTS = 16384;
+    private static final long POPUPMENU_EVENTS = (POPUPMENU_CANCELED_EVENTS |
+                                                 POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS |
+                                                 POPUPMENU_WILL_BECOME_VISIBLE_EVENTS);
+
+    /* These use their own numbering scheme, to ensure sufficient expansion room */
+    private static final long PROPERTY_NAME_CHANGE_EVENTS = 1;
+    private static final long PROPERTY_DESCRIPTION_CHANGE_EVENTS = 2;
+    private static final long PROPERTY_STATE_CHANGE_EVENTS = 4;
+    private static final long PROPERTY_VALUE_CHANGE_EVENTS = 8;
+    private static final long PROPERTY_SELECTION_CHANGE_EVENTS = 16;
+    private static final long PROPERTY_TEXT_CHANGE_EVENTS = 32;
+    private static final long PROPERTY_CARET_CHANGE_EVENTS = 64;
+    private static final long PROPERTY_VISIBLEDATA_CHANGE_EVENTS = 128;
+    private static final long PROPERTY_CHILD_CHANGE_EVENTS = 256;
+    private static final long PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS = 512;
+
+
+    private static final long PROPERTY_EVENTS = (PROPERTY_NAME_CHANGE_EVENTS |
+                                                PROPERTY_DESCRIPTION_CHANGE_EVENTS |
+                                                PROPERTY_STATE_CHANGE_EVENTS |
+                                                PROPERTY_VALUE_CHANGE_EVENTS |
+                                                PROPERTY_SELECTION_CHANGE_EVENTS |
+                                                PROPERTY_TEXT_CHANGE_EVENTS |
+                                                PROPERTY_CARET_CHANGE_EVENTS |
+                                                PROPERTY_VISIBLEDATA_CHANGE_EVENTS |
+                                                PROPERTY_CHILD_CHANGE_EVENTS |
+                                                PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS);
+
+    /**
+     * The EventHandler class listens for Java events and
+     * forwards them to the AT
+     */
+    private class EventHandler implements PropertyChangeListener,
+                                          FocusListener, CaretListener,
+                                          MenuListener, PopupMenuListener,
+                                          MouseListener, WindowListener,
+                                          ChangeListener {
+
+        private AccessBridge accessBridge;
+        private long javaEventMask = 0;
+        private long accessibilityEventMask = 0;
+
+        EventHandler(AccessBridge bridge) {
+            accessBridge = bridge;
+
+            // Register to receive WINDOW_OPENED and WINDOW_CLOSED
+            // events.  Add the event source as a native window
+            // handler is it implements NativeWindowHandler.
+            // SwingEventMonitor.addWindowListener(this);
+        }
+
+        // --------- Event Notification Registration methods
+
+        /**
+         * Invoked the first time a window is made visible.
+         */
+        public void windowOpened(WindowEvent e) {
+            // If the window is a NativeWindowHandler, add it.
+            Object o = null;
+            if (e != null)
+                o = e.getSource();
+            if (o instanceof NativeWindowHandler) {
+                addNativeWindowHandler((NativeWindowHandler)o);
+            }
+        }
+
+        /**
+         * Invoked when the user attempts to close the window
+         * from the window's system menu.  If the program does not
+         * explicitly hide or dispose the window while processing
+         * this event, the window close operation will be canceled.
+         */
+        public void windowClosing(WindowEvent e) {}
+
+        /**
+         * Invoked when a window has been closed as the result
+         * of calling dispose on the window.
+         */
+        public void windowClosed(WindowEvent e) {
+            // If the window is a NativeWindowHandler, remove it.
+            Object o = null;
+            if (e != null)
+                o = e.getSource();
+            if (o instanceof NativeWindowHandler) {
+                removeNativeWindowHandler((NativeWindowHandler)o);
+            }
+        }
+
+        /**
+         * Invoked when a window is changed from a normal to a
+         * minimized state. For many platforms, a minimized window
+         * is displayed as the icon specified in the window's
+         * iconImage property.
+         * @see java.awt.Frame#setIconImage
+         */
+        public void windowIconified(WindowEvent e) {}
+
+        /**
+         * Invoked when a window is changed from a minimized
+         * to a normal state.
+         */
+        public void windowDeiconified(WindowEvent e) {}
+
+        /**
+         * Invoked when the Window is set to be the active Window. Only a Frame or
+         * a Dialog can be the active Window. The native windowing system may
+         * denote the active Window or its children with special decorations, such
+         * as a highlighted title bar. The active Window is always either the
+         * focused Window, or the first Frame or Dialog that is an owner of the
+         * focused Window.
+         */
+        public void windowActivated(WindowEvent e) {}
+
+        /**
+         * Invoked when a Window is no longer the active Window. Only a Frame or a
+         * Dialog can be the active Window. The native windowing system may denote
+         * the active Window or its children with special decorations, such as a
+         * highlighted title bar. The active Window is always either the focused
+         * Window, or the first Frame or Dialog that is an owner of the focused
+         * Window.
+         */
+        public void windowDeactivated(WindowEvent e) {}
+
+        /**
+         * Turn on event monitoring for the event type passed in
+         * If necessary, add the appropriate event listener (if
+         * no other event of that type is being listened for)
+         */
+        void addJavaEventNotification(long type) {
+            long newEventMask = javaEventMask | type;
+            /*
+            if ( ((javaEventMask & PROPERTY_EVENTS) == 0) &&
+                 ((newEventMask & PROPERTY_EVENTS) != 0) ) {
+                AccessibilityEventMonitor.addPropertyChangeListener(this);
+            }
+            */
+            if ( ((javaEventMask & FOCUS_EVENTS) == 0) &&
+                ((newEventMask & FOCUS_EVENTS) != 0) ) {
+                SwingEventMonitor.addFocusListener(this);
+            }
+            if ( ((javaEventMask & CARET_EVENTS) == 0) &&
+                ((newEventMask & CARET_EVENTS) != 0) ) {
+                SwingEventMonitor.addCaretListener(this);
+            }
+            if ( ((javaEventMask & MOUSE_EVENTS) == 0) &&
+                ((newEventMask & MOUSE_EVENTS) != 0) ) {
+                SwingEventMonitor.addMouseListener(this);
+            }
+            if ( ((javaEventMask & MENU_EVENTS) == 0) &&
+                ((newEventMask & MENU_EVENTS) != 0) ) {
+                SwingEventMonitor.addMenuListener(this);
+                SwingEventMonitor.addPopupMenuListener(this);
+            }
+            if ( ((javaEventMask & POPUPMENU_EVENTS) == 0) &&
+                ((newEventMask & POPUPMENU_EVENTS) != 0) ) {
+                SwingEventMonitor.addPopupMenuListener(this);
+            }
+
+            javaEventMask = newEventMask;
+        }
+
+        /**
+         * Turn off event monitoring for the event type passed in
+         * If necessary, remove the appropriate event listener (if
+         * no other event of that type is being listened for)
+         */
+        void removeJavaEventNotification(long type) {
+            long newEventMask = javaEventMask & (~type);
+            /*
+            if ( ((javaEventMask & PROPERTY_EVENTS) != 0) &&
+                 ((newEventMask & PROPERTY_EVENTS) == 0) ) {
+                AccessibilityEventMonitor.removePropertyChangeListener(this);
+            }
+            */
+            if (((javaEventMask & FOCUS_EVENTS) != 0) &&
+                ((newEventMask & FOCUS_EVENTS) == 0)) {
+                SwingEventMonitor.removeFocusListener(this);
+            }
+            if (((javaEventMask & CARET_EVENTS) != 0) &&
+                ((newEventMask & CARET_EVENTS) == 0)) {
+                SwingEventMonitor.removeCaretListener(this);
+            }
+            if (((javaEventMask & MOUSE_EVENTS) == 0) &&
+                ((newEventMask & MOUSE_EVENTS) != 0)) {
+                SwingEventMonitor.removeMouseListener(this);
+            }
+            if (((javaEventMask & MENU_EVENTS) == 0) &&
+                ((newEventMask & MENU_EVENTS) != 0)) {
+                SwingEventMonitor.removeMenuListener(this);
+            }
+            if (((javaEventMask & POPUPMENU_EVENTS) == 0) &&
+                ((newEventMask & POPUPMENU_EVENTS) != 0)) {
+                SwingEventMonitor.removePopupMenuListener(this);
+            }
+
+            javaEventMask = newEventMask;
+        }
+
+        /**
+         * Turn on event monitoring for the event type passed in
+         * If necessary, add the appropriate event listener (if
+         * no other event of that type is being listened for)
+         */
+        void addAccessibilityEventNotification(long type) {
+            long newEventMask = accessibilityEventMask | type;
+            if ( ((accessibilityEventMask & PROPERTY_EVENTS) == 0) &&
+                 ((newEventMask & PROPERTY_EVENTS) != 0) ) {
+                AccessibilityEventMonitor.addPropertyChangeListener(this);
+            }
+            accessibilityEventMask = newEventMask;
+        }
+
+        /**
+         * Turn off event monitoring for the event type passed in
+         * If necessary, remove the appropriate event listener (if
+         * no other event of that type is being listened for)
+         */
+        void removeAccessibilityEventNotification(long type) {
+            long newEventMask = accessibilityEventMask & (~type);
+            if ( ((accessibilityEventMask & PROPERTY_EVENTS) != 0) &&
+                 ((newEventMask & PROPERTY_EVENTS) == 0) ) {
+                AccessibilityEventMonitor.removePropertyChangeListener(this);
+            }
+            accessibilityEventMask = newEventMask;
+        }
+
+        /**
+         *  ------- property change event glue
+         */
+        // This is invoked on the EDT , as
+        public void propertyChange(PropertyChangeEvent e) {
+
+            accessBridge.debugString("propertyChange(" + e.toString() + ") called");
+
+            if (e != null && (accessibilityEventMask & PROPERTY_EVENTS) != 0) {
+                Object o = e.getSource();
+                AccessibleContext ac;
+
+                if (o instanceof AccessibleContext) {
+                    ac = (AccessibleContext) o;
+                } else {
+                    Accessible a = Translator.getAccessible(e.getSource());
+                    if (a == null)
+                        return;
+                    else
+                        ac = a.getAccessibleContext();
+                }
+                if (ac != null) {
+                    InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext());
+
+                    accessBridge.debugString("AccessibleContext: " + ac);
+                    String propertyName = e.getPropertyName();
+
+                    if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) {
+                        int oldValue = 0;
+                        int newValue = 0;
+
+                        if (e.getOldValue() instanceof Integer) {
+                            oldValue = ((Integer) e.getOldValue()).intValue();
+                        }
+                        if (e.getNewValue() instanceof Integer) {
+                            newValue = ((Integer) e.getNewValue()).intValue();
+                        }
+                        accessBridge.debugString(" - about to call propertyCaretChange()");
+                        accessBridge.debugString("   old value: " + oldValue + "new value: " + newValue);
+                        accessBridge.propertyCaretChange(e, ac, oldValue, newValue);
+
+                    } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY) == 0) {
+                        String oldValue = null;
+                        String newValue = null;
+
+                        if (e.getOldValue() != null) {
+                            oldValue = e.getOldValue().toString();
+                        }
+                        if (e.getNewValue() != null) {
+                            newValue = e.getNewValue().toString();
+                        }
+                        accessBridge.debugString(" - about to call propertyDescriptionChange()");
+                        accessBridge.debugString("   old value: " + oldValue + "new value: " + newValue);
+                        accessBridge.propertyDescriptionChange(e, ac, oldValue, newValue);
+
+                    } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_NAME_PROPERTY) == 0) {
+                        String oldValue = null;
+                        String newValue = null;
+
+                        if (e.getOldValue() != null) {
+                            oldValue = e.getOldValue().toString();
+                        }
+                        if (e.getNewValue() != null) {
+                            newValue = e.getNewValue().toString();
+                        }
+                        accessBridge.debugString(" - about to call propertyNameChange()");
+                        accessBridge.debugString("   old value: " + oldValue + " new value: " + newValue);
+                        accessBridge.propertyNameChange(e, ac, oldValue, newValue);
+
+                    } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY) == 0) {
+                        accessBridge.debugString(" - about to call propertySelectionChange() " + ac +  "   " + Thread.currentThread() + "   " + e.getSource());
+
+                        accessBridge.propertySelectionChange(e, ac);
+
+                    } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_STATE_PROPERTY) == 0) {
+                        String oldValue = null;
+                        String newValue = null;
+
+                        // Localization fix requested by Oliver for EA-1
+                        if (e.getOldValue() != null) {
+                            AccessibleState oldState = (AccessibleState) e.getOldValue();
+                            oldValue = oldState.toDisplayString(Locale.US);
+                        }
+                        if (e.getNewValue() != null) {
+                            AccessibleState newState = (AccessibleState) e.getNewValue();
+                            newValue = newState.toDisplayString(Locale.US);
+                        }
+
+                        accessBridge.debugString(" - about to call propertyStateChange()");
+                        accessBridge.propertyStateChange(e, ac, oldValue, newValue);
+
+                    } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0) {
+                        accessBridge.debugString(" - about to call propertyTextChange()");
+                        accessBridge.propertyTextChange(e, ac);
+
+                    } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY) == 0) {  // strings 'cause of floating point, etc.
+                        String oldValue = null;
+                        String newValue = null;
+
+                        if (e.getOldValue() != null) {
+                            oldValue = e.getOldValue().toString();
+                        }
+                        if (e.getNewValue() != null) {
+                            newValue = e.getNewValue().toString();
+                        }
+                        accessBridge.debugString(" - about to call propertyDescriptionChange()");
+                        accessBridge.propertyValueChange(e, ac, oldValue, newValue);
+
+                    } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY) == 0) {
+                        accessBridge.propertyVisibleDataChange(e, ac);
+
+                    } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) {
+                        AccessibleContext oldAC = null;
+                        AccessibleContext newAC = null;
+                        Accessible a;
+
+                        if (e.getOldValue() instanceof AccessibleContext) {
+                            oldAC = (AccessibleContext) e.getOldValue();
+                            InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());
+                        }
+                        if (e.getNewValue() instanceof AccessibleContext) {
+                            newAC = (AccessibleContext) e.getNewValue();
+                            InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());
+                        }
+                        accessBridge.debugString(" - about to call propertyChildChange()");
+                        accessBridge.debugString("   old AC: " + oldAC + "new AC: " + newAC);
+                        accessBridge.propertyChildChange(e, ac, oldAC, newAC);
+
+                    } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0) {
+                        handleActiveDescendentEvent(e, ac);
+                    }
+                }
+            }
+        }
+
+        /*
+        * Handle an ActiveDescendent PropertyChangeEvent.  This
+        * method works around a JTree bug where ActiveDescendent
+        * PropertyChangeEvents have the wrong parent.
+        */
+        private AccessibleContext prevAC = null; // previous AccessibleContext
+
+        private void handleActiveDescendentEvent(PropertyChangeEvent e,
+                                                 AccessibleContext ac) {
+            if (e == null || ac == null)
+                return;
+            AccessibleContext oldAC = null;
+            AccessibleContext newAC = null;
+            Accessible a;
+
+            // get the old active descendent
+            if (e.getOldValue() instanceof Accessible) {
+                oldAC = ((Accessible) e.getOldValue()).getAccessibleContext();
+            } else if (e.getOldValue() instanceof Component) {
+                a = Translator.getAccessible(e.getOldValue());
+                if (a != null) {
+                    oldAC = a.getAccessibleContext();
+                }
+            }
+            if (oldAC != null) {
+                Accessible parent = oldAC.getAccessibleParent();
+                if (parent instanceof JTree) {
+                    // use the previous AccessibleJTreeNode
+                    oldAC = prevAC;
+                }
+            }
+
+            // get the new active descendent
+            if (e.getNewValue() instanceof Accessible) {
+                newAC = ((Accessible) e.getNewValue()).getAccessibleContext();
+            } else if (e.getNewValue() instanceof Component) {
+                a = Translator.getAccessible(e.getNewValue());
+                if (a != null) {
+                    newAC = a.getAccessibleContext();
+                }
+            }
+            if (newAC != null) {
+                Accessible parent = newAC.getAccessibleParent();
+                if (parent instanceof JTree) {
+                    // use a new AccessibleJTreeNode with the right parent
+                    JTree tree = (JTree)parent;
+                    newAC = new AccessibleJTreeNode(tree,
+                                                    tree.getSelectionPath(),
+                                                    null);
+                }
+            }
+            prevAC = newAC;
+
+            accessBridge.debugString("  - about to call propertyActiveDescendentChange()");
+            accessBridge.debugString("   AC: " + ac);
+            accessBridge.debugString("   old AC: " + oldAC + "new AC: " + newAC);
+
+            InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());
+            InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());
+            accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC);
+        }
+
+        /**
+        *  ------- focus event glue
+        */
+        private boolean stateChangeListenerAdded = false;
+
+        public void focusGained(FocusEvent e) {
+            if (runningOnJDK1_4) {
+                processFocusGained();
+            } else {
+                if ((javaEventMask & FOCUS_GAINED_EVENTS) != 0) {
+                    Accessible a = Translator.getAccessible(e.getSource());
+                    if (a != null) {
+                        AccessibleContext context = a.getAccessibleContext();
+                        InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(e.getSource()));
+                        accessBridge.focusGained(e, context);
+                    }
+                }
+            }
+        }
+
+        public void stateChanged(ChangeEvent e) {
+            processFocusGained();
+        }
+
+        private void processFocusGained() {
+            Component focusOwner = KeyboardFocusManager.
+            getCurrentKeyboardFocusManager().getFocusOwner();
+            if (focusOwner == null) {
+                return;
+            }
+
+            // Only menus and popup selections are handled by the JRootPane.
+            if (focusOwner instanceof JRootPane) {
+                MenuElement [] path =
+                MenuSelectionManager.defaultManager().getSelectedPath();
+                if (path.length > 1) {
+                    Component penult = path[path.length-2].getComponent();
+                    Component last = path[path.length-1].getComponent();
+
+                    if (last instanceof JPopupMenu) {
+                        // This is a popup with nothing in the popup
+                        // selected. The menu itself is selected.
+                        FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED);
+                        AccessibleContext context = penult.getAccessibleContext();
+                        InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult));
+                        accessBridge.focusGained(e, context);
+                    } else if (penult instanceof JPopupMenu) {
+                        // This is a popup with an item selected
+                        FocusEvent e =
+                        new FocusEvent(last, FocusEvent.FOCUS_GAINED);
+                        accessBridge.debugString(" - about to call focusGained()");
+                        AccessibleContext focusedAC = last.getAccessibleContext();
+                        InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last));
+                        accessBridge.debugString("   AC: " + focusedAC);
+                        accessBridge.focusGained(e, focusedAC);
+                    }
+                }
+            } else {
+                // The focus owner has the selection.
+                if (focusOwner instanceof Accessible) {
+                    FocusEvent e = new FocusEvent(focusOwner,
+                                                  FocusEvent.FOCUS_GAINED);
+                    accessBridge.debugString(" - about to call focusGained()");
+                    AccessibleContext focusedAC = focusOwner.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner));
+                    accessBridge.debugString("   AC: " + focusedAC);
+                    accessBridge.focusGained(e, focusedAC);
+                }
+            }
+        }
+
+        public void focusLost(FocusEvent e) {
+            if (e != null && (javaEventMask & FOCUS_LOST_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    accessBridge.debugString(" - about to call focusLost()");
+                    accessBridge.debugString("   AC: " + a.getAccessibleContext());
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.focusLost(e, context);
+                }
+            }
+        }
+
+        /**
+         *  ------- caret event glue
+         */
+        public void caretUpdate(CaretEvent e) {
+            if (e != null && (javaEventMask & CARET_UPATE_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.caretUpdate(e, context);
+                }
+            }
+        }
+
+    /**
+     *  ------- mouse event glue
+     */
+
+        public void mouseClicked(MouseEvent e) {
+            if (e != null && (javaEventMask & MOUSE_CLICKED_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.mouseClicked(e, context);
+                }
+            }
+        }
+
+        public void mouseEntered(MouseEvent e) {
+            if (e != null && (javaEventMask & MOUSE_ENTERED_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.mouseEntered(e, context);
+                }
+            }
+        }
+
+        public void mouseExited(MouseEvent e) {
+            if (e != null && (javaEventMask & MOUSE_EXITED_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.mouseExited(e, context);
+                }
+            }
+        }
+
+        public void mousePressed(MouseEvent e) {
+            if (e != null && (javaEventMask & MOUSE_PRESSED_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.mousePressed(e, context);
+                }
+            }
+        }
+
+        public void mouseReleased(MouseEvent e) {
+            if (e != null && (javaEventMask & MOUSE_RELEASED_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.mouseReleased(e, context);
+                }
+            }
+        }
+
+        /**
+         *  ------- menu event glue
+         */
+        public void menuCanceled(MenuEvent e) {
+            if (e != null && (javaEventMask & MENU_CANCELED_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.menuCanceled(e, context);
+                }
+            }
+        }
+
+        public void menuDeselected(MenuEvent e) {
+            if (e != null && (javaEventMask & MENU_DESELECTED_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.menuDeselected(e, context);
+                }
+            }
+        }
+
+        public void menuSelected(MenuEvent e) {
+            if (e != null && (javaEventMask & MENU_SELECTED_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.menuSelected(e, context);
+                }
+            }
+        }
+
+        public void popupMenuCanceled(PopupMenuEvent e) {
+            if (e != null && (javaEventMask & POPUPMENU_CANCELED_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.popupMenuCanceled(e, context);
+                }
+            }
+        }
+
+        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+            if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.popupMenuWillBecomeInvisible(e, context);
+                }
+            }
+        }
+
+        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+            if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_VISIBLE_EVENTS) != 0) {
+                Accessible a = Translator.getAccessible(e.getSource());
+                if (a != null) {
+                    AccessibleContext context = a.getAccessibleContext();
+                    InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
+                    accessBridge.popupMenuWillBecomeVisible(e, context);
+                }
+            }
+        }
+
+    } // End of EventHandler Class
+
+    // --------- Event Notification Registration methods
+
+    /**
+     *  Wrapper method around eventHandler.addJavaEventNotification()
+     */
+    private void addJavaEventNotification(final long type) {
+        EventQueue.invokeLater(new Runnable() {
+            public void run(){
+                eventHandler.addJavaEventNotification(type);
+            }
+        });
+    }
+
+    /**
+     *  Wrapper method around eventHandler.removeJavaEventNotification()
+     */
+    private void removeJavaEventNotification(final long type) {
+        EventQueue.invokeLater(new Runnable() {
+            public void run(){
+                eventHandler.removeJavaEventNotification(type);
+            }
+        });
+    }
+
+
+    /**
+     *  Wrapper method around eventHandler.addAccessibilityEventNotification()
+     */
+    private void addAccessibilityEventNotification(final long type) {
+        EventQueue.invokeLater(new Runnable() {
+            public void run(){
+                eventHandler.addAccessibilityEventNotification(type);
+            }
+        });
+    }
+
+    /**
+     *  Wrapper method around eventHandler.removeAccessibilityEventNotification()
+     */
+    private void removeAccessibilityEventNotification(final long type) {
+        EventQueue.invokeLater(new Runnable() {
+            public void run(){
+                eventHandler.removeAccessibilityEventNotification(type);
+            }
+        });
+    }
+
+    /**
+     ******************************************************
+     * All AccessibleRoles
+     *
+     * We shouldn't have to do this since it requires us
+     * to synchronize the allAccessibleRoles array when
+     * the AccessibleRoles class interface changes. However,
+     * there is no Accessibility API method to get all
+     * AccessibleRoles
+     ******************************************************
+     */
+    private AccessibleRole [] allAccessibleRoles = {
+    /**
+     * Object is used to alert the user about something.
+     */
+    AccessibleRole.ALERT,
+
+    /**
+     * The header for a column of data.
+     */
+    AccessibleRole.COLUMN_HEADER,
+
+    /**
+     * Object that can be drawn into and is used to trap
+     * events.
+     * @see #FRAME
+     * @see #GLASS_PANE
+     * @see #LAYERED_PANE
+     */
+    AccessibleRole.CANVAS,
+
+    /**
+     * A list of choices the user can select from.  Also optionally
+     * allows the user to enter a choice of their own.
+     */
+    AccessibleRole.COMBO_BOX,
+
+    /**
+     * An iconified internal frame in a DESKTOP_PANE.
+     * @see #DESKTOP_PANE
+     * @see #INTERNAL_FRAME
+     */
+    AccessibleRole.DESKTOP_ICON,
+
+    /**
+     * A frame-like object that is clipped by a desktop pane.  The
+     * desktop pane, internal frame, and desktop icon objects are
+     * often used to create multiple document interfaces within an
+     * application.
+     * @see #DESKTOP_ICON
+     * @see #DESKTOP_PANE
+     * @see #FRAME
+     */
+    AccessibleRole.INTERNAL_FRAME,
+
+    /**
+     * A pane that supports internal frames and
+     * iconified versions of those internal frames.
+     * @see #DESKTOP_ICON
+     * @see #INTERNAL_FRAME
+     */
+    AccessibleRole.DESKTOP_PANE,
+
+    /**
+     * A specialized pane whose primary use is inside a DIALOG
+     * @see #DIALOG
+     */
+    AccessibleRole.OPTION_PANE,
+
+    /**
+     * A top level window with no title or border.
+     * @see #FRAME
+     * @see #DIALOG
+     */
+    AccessibleRole.WINDOW,
+
+    /**
+     * A top level window with a title bar, border, menu bar, etc.  It is
+     * often used as the primary window for an application.
+     * @see #DIALOG
+     * @see #CANVAS
+     * @see #WINDOW
+     */
+    AccessibleRole.FRAME,
+
+    /**
+     * A top level window with title bar and a border.  A dialog is similar
+     * to a frame, but it has fewer properties and is often used as a
+     * secondary window for an application.
+     * @see #FRAME
+     * @see #WINDOW
+     */
+    AccessibleRole.DIALOG,
+
+    /**
+     * A specialized dialog that lets the user choose a color.
+     */
+    AccessibleRole.COLOR_CHOOSER,
+
+
+    /**
+     * A pane that allows the user to navigate through
+     * and select the contents of a directory.  May be used
+     * by a file chooser.
+     * @see #FILE_CHOOSER
+     */
+    AccessibleRole.DIRECTORY_PANE,
+
+    /**
+     * A specialized dialog that displays the files in the directory
+     * and lets the user select a file, browse a different directory,
+     * or specify a filename.  May use the directory pane to show the
+     * contents of a directory.
+     * @see #DIRECTORY_PANE
+     */
+    AccessibleRole.FILE_CHOOSER,
+
+    /**
+     * An object that fills up space in a user interface.  It is often
+     * used in interfaces to tweak the spacing between components,
+     * but serves no other purpose.
+     */
+    AccessibleRole.FILLER,
+
+    /**
+     * A hypertext anchor
+     */
+    // AccessibleRole.HYPERLINK,
+
+    /**
+     * A small fixed size picture, typically used to decorate components.
+     */
+    AccessibleRole.ICON,
+
+    /**
+     * An object used to present an icon or short string in an interface.
+     */
+    AccessibleRole.LABEL,
+
+    /**
+     * A specialized pane that has a glass pane and a layered pane as its
+     * children.
+     * @see #GLASS_PANE
+     * @see #LAYERED_PANE
+     */
+    AccessibleRole.ROOT_PANE,
+
+    /**
+     * A pane that is guaranteed to be painted on top
+     * of all panes beneath it.
+     * @see #ROOT_PANE
+     * @see #CANVAS
+     */
+    AccessibleRole.GLASS_PANE,
+
+    /**
+     * A specialized pane that allows its children to be drawn in layers,
+     * providing a form of stacking order.  This is usually the pane that
+     * holds the menu bar as well as the pane that contains most of the
+     * visual components in a window.
+     * @see #GLASS_PANE
+     * @see #ROOT_PANE
+     */
+    AccessibleRole.LAYERED_PANE,
+
+    /**
+     * An object that presents a list of objects to the user and allows the
+     * user to select one or more of them.  A list is usually contained
+     * within a scroll pane.
+     * @see #SCROLL_PANE
+     * @see #LIST_ITEM
+     */
+    AccessibleRole.LIST,
+
+    /**
+     * An object that presents an element in a list.  A list is usually
+     * contained within a scroll pane.
+     * @see #SCROLL_PANE
+     * @see #LIST
+     */
+    AccessibleRole.LIST_ITEM,
+
+    /**
+     * An object usually drawn at the top of the primary dialog box of
+     * an application that contains a list of menus the user can choose
+     * from.  For example, a menu bar might contain menus for "File,"
+     * "Edit," and "Help."
+     * @see #MENU
+     * @see #POPUP_MENU
+     * @see #LAYERED_PANE
+     */
+    AccessibleRole.MENU_BAR,
+
+    /**
+     * A temporary window that is usually used to offer the user a
+     * list of choices, and then hides when the user selects one of
+     * those choices.
+     * @see #MENU
+     * @see #MENU_ITEM
+     */
+    AccessibleRole.POPUP_MENU,
+
+    /**
+     * An object usually found inside a menu bar that contains a list
+     * of actions the user can choose from.  A menu can have any object
+     * as its children, but most often they are menu items, other menus,
+     * or rudimentary objects such as radio buttons, check boxes, or
+     * separators.  For example, an application may have an "Edit" menu
+     * that contains menu items for "Cut" and "Paste."
+     * @see #MENU_BAR
+     * @see #MENU_ITEM
+     * @see #SEPARATOR
+     * @see #RADIO_BUTTON
+     * @see #CHECK_BOX
+     * @see #POPUP_MENU
+     */
+    AccessibleRole.MENU,
+
+    /**
+     * An object usually contained in a menu that presents an action
+     * the user can choose.  For example, the "Cut" menu item in an
+     * "Edit" menu would be an action the user can select to cut the
+     * selected area of text in a document.
+     * @see #MENU_BAR
+     * @see #SEPARATOR
+     * @see #POPUP_MENU
+     */
+    AccessibleRole.MENU_ITEM,
+
+    /**
+     * An object usually contained in a menu to provide a visual
+     * and logical separation of the contents in a menu.  For example,
+     * the "File" menu of an application might contain menu items for
+     * "Open," "Close," and "Exit," and will place a separator between
+     * "Close" and "Exit" menu items.
+     * @see #MENU
+     * @see #MENU_ITEM
+     */
+    AccessibleRole.SEPARATOR,
+
+    /**
+     * An object that presents a series of panels (or page tabs), one at a
+     * time, through some mechanism provided by the object.  The most common
+     * mechanism is a list of tabs at the top of the panel.  The children of
+     * a page tab list are all page tabs.
+     * @see #PAGE_TAB
+     */
+    AccessibleRole.PAGE_TAB_LIST,
+
+    /**
+     * An object that is a child of a page tab list.  Its sole child is
+     * the panel that is to be presented to the user when the user
+     * selects the page tab from the list of tabs in the page tab list.
+     * @see #PAGE_TAB_LIST
+     */
+    AccessibleRole.PAGE_TAB,
+
+    /**
+     * A generic container that is often used to group objects.
+     */
+    AccessibleRole.PANEL,
+
+    /**
+     * An object used to indicate how much of a task has been completed.
+     */
+    AccessibleRole.PROGRESS_BAR,
+
+    /**
+     * A text object used for passwords, or other places where the
+     * text contents is not shown visibly to the user
+     */
+    AccessibleRole.PASSWORD_TEXT,
+
+    /**
+     * An object the user can manipulate to tell the application to do
+     * something.
+     * @see #CHECK_BOX
+     * @see #TOGGLE_BUTTON
+     * @see #RADIO_BUTTON
+     */
+    AccessibleRole.PUSH_BUTTON,
+
+    /**
+     * A specialized push button that can be checked or unchecked, but
+     * does not provide a separate indicator for the current state.
+     * @see #PUSH_BUTTON
+     * @see #CHECK_BOX
+     * @see #RADIO_BUTTON
+     */
+    AccessibleRole.TOGGLE_BUTTON,
+
+    /**
+     * A choice that can be checked or unchecked and provides a
+     * separate indicator for the current state.
+     * @see #PUSH_BUTTON
+     * @see #TOGGLE_BUTTON
+     * @see #RADIO_BUTTON
+     */
+    AccessibleRole.CHECK_BOX,
+
+    /**
+     * A specialized check box that will cause other radio buttons in the
+     * same group to become unchecked when this one is checked.
+     * @see #PUSH_BUTTON
+     * @see #TOGGLE_BUTTON
+     * @see #CHECK_BOX
+     */
+    AccessibleRole.RADIO_BUTTON,
+
+    /**
+     * The header for a row of data.
+     */
+    AccessibleRole.ROW_HEADER,
+
+    /**
+     * An object that allows a user to incrementally view a large amount
+     * of information.  Its children can include scroll bars and a viewport.
+     * @see #SCROLL_BAR
+     * @see #VIEWPORT
+     */
+    AccessibleRole.SCROLL_PANE,
+
+    /**
+     * An object usually used to allow a user to incrementally view a
+     * large amount of data.  Usually used only by a scroll pane.
+     * @see #SCROLL_PANE
+     */
+    AccessibleRole.SCROLL_BAR,
+
+    /**
+     * An object usually used in a scroll pane.  It represents the portion
+     * of the entire data that the user can see.  As the user manipulates
+     * the scroll bars, the contents of the viewport can change.
+     * @see #SCROLL_PANE
+     */
+    AccessibleRole.VIEWPORT,
+
+    /**
+     * An object that allows the user to select from a bounded range.  For
+     * example, a slider might be used to select a number between 0 and 100.
+     */
+    AccessibleRole.SLIDER,
+
+    /**
+     * A specialized panel that presents two other panels at the same time.
+     * Between the two panels is a divider the user can manipulate to make
+     * one panel larger and the other panel smaller.
+     */
+    AccessibleRole.SPLIT_PANE,
+
+    /**
+     * An object used to present information in terms of rows and columns.
+     * An example might include a spreadsheet application.
+     */
+    AccessibleRole.TABLE,
+
+    /**
+     * An object that presents text to the user.  The text is usually
+     * editable by the user as opposed to a label.
+     * @see #LABEL
+     */
+    AccessibleRole.TEXT,
+
+    /**
+     * An object used to present hierarchical information to the user.
+     * The individual nodes in the tree can be collapsed and expanded
+     * to provide selective disclosure of the tree's contents.
+     */
+    AccessibleRole.TREE,
+
+    /**
+     * A bar or palette usually composed of push buttons or toggle buttons.
+     * It is often used to provide the most frequently used functions for an
+     * application.
+     */
+    AccessibleRole.TOOL_BAR,
+
+    /**
+     * An object that provides information about another object.  The
+     * accessibleDescription property of the tool tip is often displayed
+     * to the user in a small "help bubble" when the user causes the
+     * mouse to hover over the object associated with the tool tip.
+     */
+    AccessibleRole.TOOL_TIP,
+
+    /**
+     * An AWT component, but nothing else is known about it.
+     * @see #SWING_COMPONENT
+     * @see #UNKNOWN
+     */
+    AccessibleRole.AWT_COMPONENT,
+
+    /**
+     * A Swing component, but nothing else is known about it.
+     * @see #AWT_COMPONENT
+     * @see #UNKNOWN
+     */
+    AccessibleRole.SWING_COMPONENT,
+
+    /**
+     * The object contains some Accessible information, but its role is
+     * not known.
+     * @see #AWT_COMPONENT
+     * @see #SWING_COMPONENT
+     */
+    AccessibleRole.UNKNOWN,
+
+    // These roles are only available in JDK 1.4
+
+    /**
+     * A STATUS_BAR is an simple component that can contain
+     * multiple labels of status information to the user.
+     AccessibleRole.STATUS_BAR,
+
+     /**
+     * A DATE_EDITOR is a component that allows users to edit
+     * java.util.Date and java.util.Time objects
+     AccessibleRole.DATE_EDITOR,
+
+     /**
+     * A SPIN_BOX is a simple spinner component and its main use
+     * is for simple numbers.
+     AccessibleRole.SPIN_BOX,
+
+     /**
+     * A FONT_CHOOSER is a component that lets the user pick various
+     * attributes for fonts.
+     AccessibleRole.FONT_CHOOSER,
+
+     /**
+     * A GROUP_BOX is a simple container that contains a border
+     * around it and contains components inside it.
+     AccessibleRole.GROUP_BOX
+
+     /**
+     * Since JDK 1.5
+     *
+     * A text header
+
+     AccessibleRole.HEADER,
+
+     /**
+     * A text footer
+
+     AccessibleRole.FOOTER,
+
+     /**
+     * A text paragraph
+
+     AccessibleRole.PARAGRAPH,
+
+     /**
+     * A ruler is an object used to measure distance
+
+     AccessibleRole.RULER,
+
+     /**
+     * A role indicating the object acts as a formula for
+     * calculating a value.  An example is a formula in
+     * a spreadsheet cell.
+     AccessibleRole.EDITBAR
+    */
+    };
+
+    /**
+     * This class implements accessibility support for the
+     * <code>JTree</code> child.  It provides an implementation of the
+     * Java Accessibility API appropriate to tree nodes.
+     *
+     * Copied from JTree.java to work around a JTree bug where
+     * ActiveDescendent PropertyChangeEvents contain the wrong
+     * parent.
+     */
+    /**
+     * This class in invoked on the EDT as its part of ActiveDescendant,
+     * hence the calls do not need to be specifically made on the EDT
+     */
+    private class AccessibleJTreeNode extends AccessibleContext
+        implements Accessible, AccessibleComponent, AccessibleSelection,
+                   AccessibleAction {
+
+        private JTree tree = null;
+        private TreeModel treeModel = null;
+        private Object obj = null;
+        private TreePath path = null;
+        private Accessible accessibleParent = null;
+        private int index = 0;
+        private boolean isLeaf = false;
+
+        /**
+         *  Constructs an AccessibleJTreeNode
+         */
+        AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) {
+            tree = t;
+            path = p;
+            accessibleParent = ap;
+            if (t != null)
+                treeModel = t.getModel();
+            if (p != null) {
+                obj = p.getLastPathComponent();
+                if (treeModel != null && obj != null) {
+                    isLeaf = treeModel.isLeaf(obj);
+                }
+            }
+            debugString("AccessibleJTreeNode: name = "+getAccessibleName()+"; TreePath = "+p+"; parent = "+ap);
+        }
+
+        private TreePath getChildTreePath(int i) {
+            // Tree nodes can't be so complex that they have
+            // two sets of children -> we're ignoring that case
+            if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {
+                return null;
+            } else {
+                Object childObj = treeModel.getChild(obj, i);
+                Object[] objPath = path.getPath();
+                Object[] objChildPath = new Object[objPath.length+1];
+                java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
+                objChildPath[objChildPath.length-1] = childObj;
+                return new TreePath(objChildPath);
+            }
+        }
+
+        /**
+         * Get the AccessibleContext associated with this tree node.
+         * In the implementation of the Java Accessibility API for
+         * this class, return this object, which is its own
+         * AccessibleContext.
+         *
+         * @return this object
+        */
+        public AccessibleContext getAccessibleContext() {
+            return this;
+        }
+
+        private AccessibleContext getCurrentAccessibleContext() {
+            Component c = getCurrentComponent();
+            if (c instanceof Accessible) {
+               return (c.getAccessibleContext());
+            } else {
+                return null;
+            }
+        }
+
+        private Component getCurrentComponent() {
+            debugString("AccessibleJTreeNode: getCurrentComponent");
+            // is the object visible?
+            // if so, get row, selected, focus & leaf state,
+            // and then get the renderer component and return it
+            if (tree != null && tree.isVisible(path)) {
+                TreeCellRenderer r = tree.getCellRenderer();
+                if (r == null) {
+                    debugString("  returning null 1");
+                    return null;
+                }
+                TreeUI ui = tree.getUI();
+                if (ui != null) {
+                    int row = ui.getRowForPath(tree, path);
+                    boolean selected = tree.isPathSelected(path);
+                    boolean expanded = tree.isExpanded(path);
+                    boolean hasFocus = false; // how to tell?? -PK
+                    Component retval = r.getTreeCellRendererComponent(tree, obj,
+                                                                      selected, expanded,
+                                                                      isLeaf, row, hasFocus);
+                    debugString("  returning = "+retval.getClass());
+                    return retval;
+                }
+            }
+            debugString("  returning null 2");
+            return null;
+        }
+
+        // AccessibleContext methods
+
+        /**
+         * Get the accessible name of this object.
+         *
+         * @return the localized name of the object; null if this
+         * object does not have a name
+         */
+        public String getAccessibleName() {
+            debugString("AccessibleJTreeNode: getAccessibleName");
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                String name = ac.getAccessibleName();
+                if ((name != null) && (!name.isEmpty())) {
+                    String retval = ac.getAccessibleName();
+                    debugString("    returning "+retval);
+                    return retval;
+                } else {
+                    return null;
+                }
+            }
+            if ((accessibleName != null) && (accessibleName.isEmpty())) {
+                return accessibleName;
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Set the localized accessible name of this object.
+         *
+         * @param s the new localized name of the object.
+         */
+        public void setAccessibleName(String s) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                ac.setAccessibleName(s);
+            } else {
+                super.setAccessibleName(s);
+            }
+        }
+
+        //
+        // *** should check tooltip text for desc. (needs MouseEvent)
+        //
+        /**
+         * Get the accessible description of this object.
+         *
+         * @return the localized description of the object; null if
+         * this object does not have a description
+         */
+        public String getAccessibleDescription() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                return ac.getAccessibleDescription();
+            } else {
+                return super.getAccessibleDescription();
+            }
+        }
+
+        /**
+         * Set the accessible description of this object.
+         *
+         * @param s the new localized description of the object
+         */
+        public void setAccessibleDescription(String s) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                ac.setAccessibleDescription(s);
+            } else {
+                super.setAccessibleDescription(s);
+            }
+        }
+
+        /**
+         * Get the role of this object.
+         *
+         * @return an instance of AccessibleRole describing the role of the object
+         * @see AccessibleRole
+         */
+        public AccessibleRole getAccessibleRole() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                return ac.getAccessibleRole();
+            } else {
+                return AccessibleRole.UNKNOWN;
+            }
+        }
+
+        /**
+         * Get the state set of this object.
+         *
+         * @return an instance of AccessibleStateSet containing the
+         * current state set of the object
+         * @see AccessibleState
+         */
+        public AccessibleStateSet getAccessibleStateSet() {
+            if (tree == null)
+                return null;
+            AccessibleContext ac = getCurrentAccessibleContext();
+            AccessibleStateSet states;
+            int row = tree.getUI().getRowForPath(tree,path);
+            int lsr = tree.getLeadSelectionRow();
+            if (ac != null) {
+                states = ac.getAccessibleStateSet();
+            } else {
+                states = new AccessibleStateSet();
+            }
+            // need to test here, 'cause the underlying component
+            // is a cellRenderer, which is never showing...
+            if (isShowing()) {
+                states.add(AccessibleState.SHOWING);
+            } else if (states.contains(AccessibleState.SHOWING)) {
+                states.remove(AccessibleState.SHOWING);
+            }
+            if (isVisible()) {
+                states.add(AccessibleState.VISIBLE);
+            } else if (states.contains(AccessibleState.VISIBLE)) {
+                states.remove(AccessibleState.VISIBLE);
+            }
+            if (tree.isPathSelected(path)){
+                states.add(AccessibleState.SELECTED);
+            }
+            if (lsr == row) {
+                states.add(AccessibleState.ACTIVE);
+            }
+            if (!isLeaf) {
+                states.add(AccessibleState.EXPANDABLE);
+            }
+            if (tree.isExpanded(path)) {
+                states.add(AccessibleState.EXPANDED);
+            } else {
+                states.add(AccessibleState.COLLAPSED);
+            }
+            if (tree.isEditable()) {
+                states.add(AccessibleState.EDITABLE);
+            }
+            return states;
+        }
+
+        /**
+         * Get the Accessible parent of this object.
+         *
+         * @return the Accessible parent of this object; null if this
+         * object does not have an Accessible parent
+         */
+        public Accessible getAccessibleParent() {
+            // someone wants to know, so we need to create our parent
+            // if we don't have one (hey, we're a talented kid!)
+            if (accessibleParent == null && path != null) {
+                Object[] objPath = path.getPath();
+                if (objPath.length > 1) {
+                    Object objParent = objPath[objPath.length-2];
+                    if (treeModel != null) {
+                        index = treeModel.getIndexOfChild(objParent, obj);
+                    }
+                    Object[] objParentPath = new Object[objPath.length-1];
+                    java.lang.System.arraycopy(objPath, 0, objParentPath,
+                                               0, objPath.length-1);
+                    TreePath parentPath = new TreePath(objParentPath);
+                    accessibleParent = new AccessibleJTreeNode(tree,
+                                                               parentPath,
+                                                               null);
+                    this.setAccessibleParent(accessibleParent);
+                } else if (treeModel != null) {
+                    accessibleParent = tree; // we're the top!
+                    index = 0; // we're an only child!
+                    this.setAccessibleParent(accessibleParent);
+                }
+            }
+            return accessibleParent;
+        }
+
+        /**
+         * Get the index of this object in its accessible parent.
+         *
+         * @return the index of this object in its parent; -1 if this
+         * object does not have an accessible parent.
+         * @see #getAccessibleParent
+         */
+        public int getAccessibleIndexInParent() {
+            // index is invalid 'till we have an accessibleParent...
+            if (accessibleParent == null) {
+                getAccessibleParent();
+            }
+            if (path != null) {
+                Object[] objPath = path.getPath();
+                if (objPath.length > 1) {
+                    Object objParent = objPath[objPath.length-2];
+                    if (treeModel != null) {
+                        index = treeModel.getIndexOfChild(objParent, obj);
+                    }
+                }
+            }
+            return index;
+        }
+
+        /**
+         * Returns the number of accessible children in the object.
+         *
+         * @return the number of accessible children in the object.
+         */
+        public int getAccessibleChildrenCount() {
+            // Tree nodes can't be so complex that they have
+            // two sets of children -> we're ignoring that case
+            if (obj != null && treeModel != null) {
+                return treeModel.getChildCount(obj);
+            }
+            return 0;
+        }
+
+        /**
+         * Return the specified Accessible child of the object.
+         *
+         * @param i zero-based index of child
+         * @return the Accessible child of the object
+         */
+        public Accessible getAccessibleChild(int i) {
+            // Tree nodes can't be so complex that they have
+            // two sets of children -> we're ignoring that case
+            if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {
+                return null;
+            } else {
+                Object childObj = treeModel.getChild(obj, i);
+                Object[] objPath = path.getPath();
+                Object[] objChildPath = new Object[objPath.length+1];
+                java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
+                objChildPath[objChildPath.length-1] = childObj;
+                TreePath childPath = new TreePath(objChildPath);
+                return new AccessibleJTreeNode(tree, childPath, this);
+            }
+        }
+
+        /**
+         * Gets the locale of the component. If the component does not have
+         * a locale, then the locale of its parent is returned.
+         *
+         * @return This component's locale. If this component does not have
+         * a locale, the locale of its parent is returned.
+         * @exception IllegalComponentStateException
+         * If the Component does not have its own locale and has not yet
+         * been added to a containment hierarchy such that the locale can be
+         * determined from the containing parent.
+         * @see #setLocale
+         */
+        public Locale getLocale() {
+            if (tree == null)
+                return null;
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                return ac.getLocale();
+            } else {
+                return tree.getLocale();
+            }
+        }
+
+        /**
+         * Add a PropertyChangeListener to the listener list.
+         * The listener is registered for all properties.
+         *
+         * @param l  The PropertyChangeListener to be added
+         */
+        public void addPropertyChangeListener(PropertyChangeListener l) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                ac.addPropertyChangeListener(l);
+            } else {
+                super.addPropertyChangeListener(l);
+            }
+        }
+
+        /**
+         * Remove a PropertyChangeListener from the listener list.
+         * This removes a PropertyChangeListener that was registered
+         * for all properties.
+         *
+         * @param l  The PropertyChangeListener to be removed
+         */
+        public void removePropertyChangeListener(PropertyChangeListener l) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                ac.removePropertyChangeListener(l);
+            } else {
+                super.removePropertyChangeListener(l);
+            }
+        }
+
+        /**
+         * Get the AccessibleAction associated with this object.  In the
+         * implementation of the Java Accessibility API for this class,
+         * return this object, which is responsible for implementing the
+         * AccessibleAction interface on behalf of itself.
+         *
+         * @return this object
+         */
+        public AccessibleAction getAccessibleAction() {
+            return this;
+        }
+
+        /**
+         * Get the AccessibleComponent associated with this object.  In the
+         * implementation of the Java Accessibility API for this class,
+         * return this object, which is responsible for implementing the
+         * AccessibleComponent interface on behalf of itself.
+         *
+         * @return this object
+         */
+        public AccessibleComponent getAccessibleComponent() {
+            return this; // to override getBounds()
+        }
+
+        /**
+         * Get the AccessibleSelection associated with this object if one
+         * exists.  Otherwise return null.
+         *
+         * @return the AccessibleSelection, or null
+         */
+        public AccessibleSelection getAccessibleSelection() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null && isLeaf) {
+                return getCurrentAccessibleContext().getAccessibleSelection();
+            } else {
+                return this;
+            }
+        }
+
+        /**
+         * Get the AccessibleText associated with this object if one
+         * exists.  Otherwise return null.
+         *
+         * @return the AccessibleText, or null
+         */
+        public AccessibleText getAccessibleText() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                return getCurrentAccessibleContext().getAccessibleText();
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Get the AccessibleValue associated with this object if one
+         * exists.  Otherwise return null.
+         *
+         * @return the AccessibleValue, or null
+         */
+        public AccessibleValue getAccessibleValue() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                return getCurrentAccessibleContext().getAccessibleValue();
+            } else {
+                return null;
+            }
+        }
+
+
+            // AccessibleComponent methods
+
+        /**
+         * Get the background color of this object.
+         *
+         * @return the background color, if supported, of the object;
+         * otherwise, null
+         */
+        public Color getBackground() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                return ((AccessibleComponent) ac).getBackground();
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    return c.getBackground();
+                } else {
+                    return null;
+                }
+            }
+        }
+
+        /**
+         * Set the background color of this object.
+         *
+         * @param c the new Color for the background
+         */
+        public void setBackground(Color c) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).setBackground(c);
+            } else {
+                Component cp = getCurrentComponent();
+                if (    cp != null) {
+                    cp.setBackground(c);
+                }
+            }
+        }
+
+
+        /**
+         * Get the foreground color of this object.
+         *
+         * @return the foreground color, if supported, of the object;
+         * otherwise, null
+         */
+        public Color getForeground() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                return ((AccessibleComponent) ac).getForeground();
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    return c.getForeground();
+                } else {
+                    return null;
+                }
+            }
+        }
+
+        public void setForeground(Color c) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).setForeground(c);
+            } else {
+                Component cp = getCurrentComponent();
+                if (cp != null) {
+                    cp.setForeground(c);
+                }
+            }
+        }
+
+        public Cursor getCursor() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                return ((AccessibleComponent) ac).getCursor();
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    return c.getCursor();
+                } else {
+                    Accessible ap = getAccessibleParent();
+                    if (ap instanceof AccessibleComponent) {
+                        return ((AccessibleComponent) ap).getCursor();
+                    } else {
+                        return null;
+                    }
+                }
+            }
+        }
+
+        public void setCursor(Cursor c) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).setCursor(c);
+            } else {
+                Component cp = getCurrentComponent();
+                if (cp != null) {
+                    cp.setCursor(c);
+                }
+            }
+        }
+
+        public Font getFont() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                return ((AccessibleComponent) ac).getFont();
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    return c.getFont();
+                } else {
+                    return null;
+                }
+            }
+        }
+
+        public void setFont(Font f) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).setFont(f);
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    c.setFont(f);
+                }
+            }
+        }
+
+        public FontMetrics getFontMetrics(Font f) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                return ((AccessibleComponent) ac).getFontMetrics(f);
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    return c.getFontMetrics(f);
+                } else {
+                    return null;
+                }
+            }
+        }
+
+        public boolean isEnabled() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                return ((AccessibleComponent) ac).isEnabled();
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    return c.isEnabled();
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        public void setEnabled(boolean b) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).setEnabled(b);
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    c.setEnabled(b);
+                }
+            }
+        }
+
+        public boolean isVisible() {
+            if (tree == null)
+                return false;
+            Rectangle pathBounds = tree.getPathBounds(path);
+            Rectangle parentBounds = tree.getVisibleRect();
+            if ( pathBounds != null && parentBounds != null &&
+                 parentBounds.intersects(pathBounds) ) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        public void setVisible(boolean b) {
+        }
+
+        public boolean isShowing() {
+            return (tree.isShowing() && isVisible());
+        }
+
+        public boolean contains(Point p) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                Rectangle r = ((AccessibleComponent) ac).getBounds();
+                return r.contains(p);
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    Rectangle r = c.getBounds();
+                    return r.contains(p);
+                } else {
+                    return getBounds().contains(p);
+                }
+            }
+        }
+
+        public Point getLocationOnScreen() {
+            if (tree != null) {
+                Point treeLocation = tree.getLocationOnScreen();
+                Rectangle pathBounds = tree.getPathBounds(path);
+                if (treeLocation != null && pathBounds != null) {
+                    Point nodeLocation = new Point(pathBounds.x,
+                                                   pathBounds.y);
+                    nodeLocation.translate(treeLocation.x, treeLocation.y);
+                    return nodeLocation;
+                } else {
+                    return null;
+                }
+            } else {
+                return null;
+            }
+        }
+
+        private Point getLocationInJTree() {
+            Rectangle r = tree.getPathBounds(path);
+            if (r != null) {
+                return r.getLocation();
+            } else {
+                return null;
+            }
+        }
+
+        public Point getLocation() {
+            Rectangle r = getBounds();
+            if (r != null) {
+                return r.getLocation();
+            } else {
+                return null;
+            }
+        }
+
+        public void setLocation(Point p) {
+        }
+
+        public Rectangle getBounds() {
+            if (tree == null)
+                return null;
+            Rectangle r = tree.getPathBounds(path);
+            Accessible parent = getAccessibleParent();
+            if (parent instanceof AccessibleJTreeNode) {
+                Point parentLoc = ((AccessibleJTreeNode) parent).getLocationInJTree();
+                if (parentLoc != null && r != null) {
+                    r.translate(-parentLoc.x, -parentLoc.y);
+                } else {
+                    return null;        // not visible!
+                }
+            }
+            return r;
+        }
+
+        public void setBounds(Rectangle r) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).setBounds(r);
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    c.setBounds(r);
+                }
+            }
+        }
+
+        public Dimension getSize() {
+            return getBounds().getSize();
+        }
+
+        public void setSize (Dimension d) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).setSize(d);
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    c.setSize(d);
+                }
+            }
+        }
+
+        /**
+        * Returns the <code>Accessible</code> child, if one exists,
+        * contained at the local coordinate <code>Point</code>.
+        * Otherwise returns <code>null</code>.
+        *
+        * @param p point in local coordinates of this
+        *    <code>Accessible</code>
+        * @return the <code>Accessible</code>, if it exists,
+        *    at the specified location; else <code>null</code>
+        */
+        public Accessible getAccessibleAt(Point p) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                return ((AccessibleComponent) ac).getAccessibleAt(p);
+            } else {
+                return null;
+            }
+        }
+
+        public boolean isFocusTraversable() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                return ((AccessibleComponent) ac).isFocusTraversable();
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    return c.isFocusable();
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        public void requestFocus() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).requestFocus();
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    c.requestFocus();
+                }
+            }
+        }
+
+        public void addFocusListener(FocusListener l) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).addFocusListener(l);
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    c.addFocusListener(l);
+                }
+            }
+        }
+
+        public void removeFocusListener(FocusListener l) {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac instanceof AccessibleComponent) {
+                ((AccessibleComponent) ac).removeFocusListener(l);
+            } else {
+                Component c = getCurrentComponent();
+                if (c != null) {
+                    c.removeFocusListener(l);
+                }
+            }
+        }
+
+            // AccessibleSelection methods
+
+        /**
+         * Returns the number of items currently selected.
+         * If no items are selected, the return value will be 0.
+         *
+         * @return the number of items currently selected.
+         */
+        public int getAccessibleSelectionCount() {
+            int count = 0;
+            int childCount = getAccessibleChildrenCount();
+            for (int i = 0; i < childCount; i++) {
+                TreePath childPath = getChildTreePath(i);
+                if (tree.isPathSelected(childPath)) {
+                    count++;
+                }
+            }
+            return count;
+        }
+
+        /**
+         * Returns an Accessible representing the specified selected item
+         * in the object.  If there isn't a selection, or there are
+         * fewer items selected than the integer passed in, the return
+         * value will be null.
+         *
+         * @param i the zero-based index of selected items
+         * @return an Accessible containing the selected item
+         */
+        public Accessible getAccessibleSelection(int i) {
+            int childCount = getAccessibleChildrenCount();
+            if (i < 0 || i >= childCount) {
+                return null;        // out of range
+            }
+            int count = 0;
+            for (int j = 0; j < childCount && i >= count; j++) {
+                TreePath childPath = getChildTreePath(j);
+                if (tree.isPathSelected(childPath)) {
+                    if (count == i) {
+                        return new AccessibleJTreeNode(tree, childPath, this);
+                    } else {
+                        count++;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Returns true if the current child of this object is selected.
+         *
+         * @param i the zero-based index of the child in this Accessible
+         * object.
+         * @see AccessibleContext#getAccessibleChild
+         */
+        public boolean isAccessibleChildSelected(int i) {
+            int childCount = getAccessibleChildrenCount();
+            if (i < 0 || i >= childCount) {
+                return false;       // out of range
+            } else {
+                TreePath childPath = getChildTreePath(i);
+                return tree.isPathSelected(childPath);
+            }
+        }
+
+         /**
+         * Adds the specified selected item in the object to the object's
+         * selection.  If the object supports multiple selections,
+         * the specified item is added to any existing selection, otherwise
+         * it replaces any existing selection in the object.  If the
+         * specified item is already selected, this method has no effect.
+         *
+         * @param i the zero-based index of selectable items
+         */
+        public void addAccessibleSelection(int i) {
+            if (tree == null)
+                return;
+            TreeModel model = tree.getModel();
+            if (model != null) {
+                if (i >= 0 && i < getAccessibleChildrenCount()) {
+                    TreePath path = getChildTreePath(i);
+                    tree.addSelectionPath(path);
+                }
+            }
+        }
+
+        /**
+         * Removes the specified selected item in the object from the
+         * object's
+         * selection.  If the specified item isn't currently selected, this
+         * method has no effect.
+         *
+         * @param i the zero-based index of selectable items
+         */
+        public void removeAccessibleSelection(int i) {
+            if (tree == null)
+                return;
+            TreeModel model = tree.getModel();
+            if (model != null) {
+                if (i >= 0 && i < getAccessibleChildrenCount()) {
+                    TreePath path = getChildTreePath(i);
+                    tree.removeSelectionPath(path);
+                }
+            }
+        }
+
+        /**
+         * Clears the selection in the object, so that nothing in the
+         * object is selected.
+         */
+        public void clearAccessibleSelection() {
+            int childCount = getAccessibleChildrenCount();
+            for (int i = 0; i < childCount; i++) {
+                removeAccessibleSelection(i);
+            }
+        }
+
+        /**
+         * Causes every selected item in the object to be selected
+         * if the object supports multiple selections.
+         */
+        public void selectAllAccessibleSelection() {
+            if (tree == null)
+                return;
+            TreeModel model = tree.getModel();
+            if (model != null) {
+                int childCount = getAccessibleChildrenCount();
+                TreePath path;
+                for (int i = 0; i < childCount; i++) {
+                    path = getChildTreePath(i);
+                    tree.addSelectionPath(path);
+                }
+            }
+        }
+
+            // AccessibleAction methods
+
+        /**
+         * Returns the number of accessible actions available in this
+         * tree node.  If this node is not a leaf, there is at least
+         * one action (toggle expand), in addition to any available
+         * on the object behind the TreeCellRenderer.
+         *
+         * @return the number of Actions in this object
+         */
+        public int getAccessibleActionCount() {
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (ac != null) {
+                AccessibleAction aa = ac.getAccessibleAction();
+                if (aa != null) {
+                    return (aa.getAccessibleActionCount() + (isLeaf ? 0 : 1));
+                }
+            }
+            return isLeaf ? 0 : 1;
+        }
+
+        /**
+         * Return a description of the specified action of the tree node.
+         * If this node is not a leaf, there is at least one action
+         * description (toggle expand), in addition to any available
+         * on the object behind the TreeCellRenderer.
+         *
+         * @param i zero-based index of the actions
+         * @return a description of the action
+         */
+        public String getAccessibleActionDescription(int i) {
+            if (i < 0 || i >= getAccessibleActionCount()) {
+                return null;
+            }
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (i == 0) {
+                // TIGER - 4766636
+                // return AccessibleAction.TOGGLE_EXPAND;
+                return "toggle expand";
+            } else if (ac != null) {
+                AccessibleAction aa = ac.getAccessibleAction();
+                if (aa != null) {
+                    return aa.getAccessibleActionDescription(i - 1);
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Perform the specified Action on the tree node.  If this node
+         * is not a leaf, there is at least one action which can be
+         * done (toggle expand), in addition to any available on the
+         * object behind the TreeCellRenderer.
+         *
+         * @param i zero-based index of actions
+         * @return true if the the action was performed; else false.
+         */
+        public boolean doAccessibleAction(int i) {
+            if (i < 0 || i >= getAccessibleActionCount()) {
+                return false;
+            }
+            AccessibleContext ac = getCurrentAccessibleContext();
+            if (i == 0) {
+                if (tree.isExpanded(path)) {
+                    tree.collapsePath(path);
+                } else {
+                    tree.expandPath(path);
+                }
+                return true;
+            } else if (ac != null) {
+                AccessibleAction aa = ac.getAccessibleAction();
+                if (aa != null) {
+                    return aa.doAccessibleAction(i - 1);
+                }
+            }
+            return false;
+        }
+
+    } // inner class AccessibleJTreeNode
+
+    /**
+     * A helper class to perform {@code Callable} objects on the event dispatch thread appropriate
+     * for the provided {@code AccessibleContext}.
+     */
+    private static class InvocationUtils {
+
+        /**
+         * Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible}
+         * and waits for it to finish blocking the caller thread.
+         *
+         * @param callable   the {@code Callable} to invoke
+         * @param accessible the {@code Accessible} which would be used to find the right context
+         *                   for the task execution
+         * @param <T> type parameter for the result value
+         *
+         * @return the result of the {@code Callable} execution
+         */
+        public static <T> T invokeAndWait(final Callable<T> callable,
+                                          final Accessible accessible) {
+            if (accessible instanceof Component) {
+                return invokeAndWait(callable, (Component)accessible);
+            }
+            if (accessible instanceof AccessibleContext) {
+                // This case also covers the Translator
+                return invokeAndWait(callable, (AccessibleContext)accessible);
+            }
+            throw new RuntimeException("Unmapped Accessible used to dispatch event: " + accessible);
+        }
+
+        /**
+         * Invokes a {@code Callable} in the {@code AppContext} of the given {@code Component}
+         * and waits for it to finish blocking the caller thread.
+         *
+         * @param callable  the {@code Callable} to invoke
+         * @param component the {@code Component} which would be used to find the right context
+         *                  for the task execution
+         * @param <T> type parameter for the result value
+         *
+         * @return the result of the {@code Callable} execution
+         */
+        public static <T> T invokeAndWait(final Callable<T> callable,
+                                          final Component component) {
+            return invokeAndWait(callable, SunToolkit.targetToAppContext(component));
+        }
+
+        /**
+         * Invokes a {@code Callable} in the {@code AppContext} mapped to the given {@code AccessibleContext}
+         * and waits for it to finish blocking the caller thread.
+         *
+         * @param callable the {@code Callable} to invoke
+         * @param accessibleContext the {@code AccessibleContext} which would be used to determine the right
+         *                          context for the task execution.
+         * @param <T> type parameter for the result value
+         *
+         * @return the result of the {@code Callable} execution
+         */
+        public static <T> T invokeAndWait(final Callable<T> callable,
+                                          final AccessibleContext accessibleContext) {
+            AppContext targetContext = AWTAccessor.getAccessibleContextAccessor()
+                    .getAppContext(accessibleContext);
+            if (targetContext != null) {
+                return invokeAndWait(callable, targetContext);
+            } else {
+                // Normally this should not happen, unmapped context provided and
+                // the target AppContext is unknown.
+
+                // Try to recover in case the context is a translator.
+                if (accessibleContext instanceof Translator) {
+                    Object source = ((Translator)accessibleContext).getSource();
+                    if (source instanceof Component) {
+                        return invokeAndWait(callable, (Component)source);
+                    }
+                }
+            }
+            throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleContext);
+        }
+
+        private static <T> T invokeAndWait(final Callable<T> callable,
+                                           final AppContext targetAppContext) {
+            final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable);
+            try {
+                invokeAndWait(wrapper, targetAppContext);
+                T result = wrapper.getResult();
+                updateAppContextMap(result, targetAppContext);
+                return result;
+            } catch (final Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private static void invokeAndWait(final Runnable runnable,
+                                        final AppContext appContext)
+                throws InterruptedException, InvocationTargetException {
+
+            EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);
+            Object lock = new Object();
+            Toolkit source = Toolkit.getDefaultToolkit();
+            InvocationEvent event =
+                    new InvocationEvent(source, runnable, lock, true);
+            synchronized (lock) {
+                eq.postEvent(event);
+                lock.wait();
+            }
+
+            Throwable eventThrowable = event.getThrowable();
+            if (eventThrowable != null) {
+                throw new InvocationTargetException(eventThrowable);
+            }
+        }
+
+        /**
+         * Maps the {@code AccessibleContext} to the {@code AppContext} which should be used
+         * to dispatch events related to the {@code AccessibleContext}
+         * @param accessibleContext the {@code AccessibleContext} for the mapping
+         * @param targetContext the {@code AppContext} for the mapping
+         */
+        public static void registerAccessibleContext(final AccessibleContext accessibleContext,
+                                                     final AppContext targetContext) {
+            if (accessibleContext != null) {
+                AWTAccessor.getAccessibleContextAccessor().setAppContext(accessibleContext, targetContext);
+            }
+        }
+
+        private static <T> void updateAppContextMap(final T accessibleContext,
+                                                    final AppContext targetContext) {
+            if (accessibleContext instanceof AccessibleContext) {
+                registerAccessibleContext((AccessibleContext)accessibleContext, targetContext);
+            }
+        }
+
+        private static class CallableWrapper<T> implements Runnable {
+            private final Callable<T> callable;
+            private volatile T object;
+            private Exception e;
+
+            CallableWrapper(final Callable<T> callable) {
+                this.callable = callable;
+            }
+
+            public void run() {
+                try {
+                    if (callable != null) {
+                        object = callable.call();
+                    }
+                } catch (final Exception e) {
+                    this.e = e;
+                }
+            }
+
+            T getResult() throws Exception {
+                if (e != null)
+                    throw e;
+                return object;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedRelation.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.java.accessibility.extensions;
+
+import javax.accessibility.*;
+
+/**
+ * <P>Class AccessibleExtendedRelation contains extensions to the class
+ * AccessibleRelation that are currently not in a public API.
+ *
+ * <P>Class AccessibleRelation describes a relation between the
+ * object that implements the AccessibleRelation and one or more other
+ * objects.  The actual relations that an object has with other
+ * objects are defined as an AccessibleRelationSet, which is a composed
+ * set of AccessibleRelations.
+ * <p>The toDisplayString method allows you to obtain the localized string
+ * for a locale independent key from a predefined ResourceBundle for the
+ * keys defined in this class.
+ * <p>The constants in this class present a strongly typed enumeration
+ * of common object roles. If the constants in this class are not sufficient
+ * to describe the role of an object, a subclass should be generated
+ * from this class and it should provide constants in a similar manner.
+ *
+ */
+
+public class AccessibleExtendedRelation
+    extends AccessibleExtendedRelationConstants {
+
+    public AccessibleExtendedRelation(String s) {
+        super(s);
+    }
+
+    public AccessibleExtendedRelation(String key, Object target) {
+        super(key, target);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedRelationConstants.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.java.accessibility.extensions;
+
+import javax.accessibility.*;
+
+/**
+ * <P>Class AccessibleExtendedRelation contains extensions to the class
+ * AccessibleRelation that are currently not in a public API.
+ *
+ * <P>Class AccessibleRelation describes a relation between the
+ * object that implements the AccessibleRelation and one or more other
+ * objects.  The actual relations that an object has with other
+ * objects are defined as an AccessibleRelationSet, which is a composed
+ * set of AccessibleRelations.
+ * <p>The toDisplayString method allows you to obtain the localized string
+ * for a locale independent key from a predefined ResourceBundle for the
+ * keys defined in this class.
+ * <p>The constants in this class present a strongly typed enumeration
+ * of common object roles. If the constants in this class are not sufficient
+ * to describe the role of an object, a subclass should be generated
+ * from this class and it should provide constants in a similar manner.
+ *
+ */
+
+public abstract class AccessibleExtendedRelationConstants
+    extends AccessibleRelation {
+
+    /**
+     * Indicates that one AccessibleText object is linked to the
+     * target AccessibleText object(s). <p> A good example is a StarOffice
+     * text window with the bottom of one page, a footer, a header,
+     * and the top of another page all visible in the window.  There
+     * should be a FLOWS_TO relation from the last chunk of AccessibleText
+     * in the bottom of one page to the first AccessibleText object at the
+     * top of the next page, skipping over the AccessibleText object(s)
+     * that make up the header and footer. A corresponding FLOWS_FROM
+     * relation would link the AccessibleText object in the next page to
+     * the last one in the previous page.
+     * @see AccessibleExtendedRole.FLOWS_FROM
+     */
+    public static final String FLOWS_TO = "flowsTo";
+
+    /**
+     * Indicates that one AccessibleText object is linked to the
+     * target AccessibleText object(s).
+     * @see AccessibleExtendedRole.FLOWS_TO
+     */
+    public static final String FLOWS_FROM = "flowsFrom";
+
+    /**
+     * Indicates a component is a subwindow of a target component
+     */
+    public static final String SUBWINDOW_OF = "subwindowOf";
+
+    /**
+     * Identifies that the linkage between one AccessibleText
+     * object and the target AccessibleText object(s) has changed.
+     * @see AccessibleExtendedRole.FLOWS_TO
+     * @see AccessibleExtendedRole.FLOWS_FROM
+     */
+    public static final String FLOWS_TO_PROPERTY = "flowsToProperty";
+
+    /**
+     * Identifies that the linkage between one AccessibleText
+     * object and the target AccessibleText object(s) has changed.
+     * @see AccessibleExtendedRole.FLOWS_TO
+     * @see AccessibleExtendedRole.FLOWS_FROM
+     */
+    public static final String FLOWS_FROM_PROPERTY = "flowsFromProperty";
+
+    /**
+     * Identifies the subwindow relationship between two components
+     * has changed
+     */
+    public static final String SUBWINDOW_OF_PROPERTY = "subwindowOfProperty";
+
+    public AccessibleExtendedRelationConstants(String s) {
+        super(s);
+    }
+
+    public AccessibleExtendedRelationConstants(String key, Object target) {
+        super(key, target);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedRole.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.java.accessibility.extensions;
+
+import javax.accessibility.*;
+
+/**
+ * <P>Class AccessibleExtendedRole contains extensions to the class
+ * AccessibleRole that are currently not in a public API.
+ *
+ * <P>Class AccessibleRole determines the role of a component.  The role
+ * of a component describes its generic function. (E.G.,
+ * "push button," "table," or "list.")
+ * <p>The constants in this class present a strongly typed enumeration
+ * of common object roles.  A public constructor for this class has been
+ * purposely omitted and applications should use one of the constants
+ * from this class.  If the constants in this class are not sufficient
+ * to describe the role of an object, a subclass should be generated
+ * from this class and it should provide constants in a similar manner.
+ *
+ */
+
+public class AccessibleExtendedRole extends AccessibleExtendedRoleConstants {
+
+    public AccessibleExtendedRole(String s) {
+        super(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedRoleConstants.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.java.accessibility.extensions;
+
+import javax.accessibility.*;
+
+/**
+ * <P>Class AccessibleExtendedRole contains extensions to the class
+ * AccessibleRole that are currently not in a public API.
+ *
+ * <P>Class AccessibleRole determines the role of a component.  The role
+ * of a component describes its generic function. (E.G.,
+ * "push button," "table," or "list.")
+ * <p>The constants in this class present a strongly typed enumeration
+ * of common object roles.  A public constructor for this class has been
+ * purposely omitted and applications should use one of the constants
+ * from this class.  If the constants in this class are not sufficient
+ * to describe the role of an object, a subclass should be generated
+ * from this class and it should provide constants in a similar manner.
+ *
+ */
+
+public abstract class AccessibleExtendedRoleConstants extends AccessibleRole {
+
+    /**
+     * Indicates this component is a text header.
+     */
+    public static final AccessibleExtendedRole HEADER
+            = new AccessibleExtendedRole("Header");
+
+    /**
+     * Indicates this component is a text footer.
+     */
+    public static final AccessibleExtendedRole FOOTER
+            = new AccessibleExtendedRole("Footer");
+
+    /**
+     * Indicates this component is a text paragraph.
+     */
+    public static final AccessibleExtendedRole PARAGRAPH
+            = new AccessibleExtendedRole("Paragraph");
+
+    /**
+     * Indicates this component is a ruler.
+     */
+    public static final AccessibleExtendedRole RULER
+            = new AccessibleExtendedRole("RULER");
+
+    public AccessibleExtendedRoleConstants(String s) {
+        super(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedState.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.java.accessibility.extensions;
+
+import javax.accessibility.*;
+
+/**
+ * <P>Class AccessibleState describes a component's particular state.  The actual
+ * state of the component is defined as an AccessibleStateSet, which is a
+ * composed set of AccessibleStates.
+ * <p>The toDisplayString method allows you to obtain the localized string
+ * for a locale independent key from a predefined ResourceBundle for the
+ * keys defined in this class.
+ * <p>The constants in this class present a strongly typed enumeration
+ * of common object roles.  A public constructor for this class has been
+ * purposely omitted and applications should use one of the constants
+ * from this class.  If the constants in this class are not sufficient
+ * to describe the role of an object, a subclass should be generated
+ * from this class and it should provide constants in a similar manner.
+ *
+ */
+
+public abstract class AccessibleExtendedState
+    extends AccessibleExtendedStateConstants {
+
+    public AccessibleExtendedState(String s) {
+        super(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/extensions/AccessibleExtendedStateConstants.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.java.accessibility.extensions;
+
+import javax.accessibility.*;
+
+/**
+ * <P>Class AccessibleState describes a component's particular state.  The actual
+ * state of the component is defined as an AccessibleStateSet, which is a
+ * composed set of AccessibleStates.
+ * <p>The toDisplayString method allows you to obtain the localized string
+ * for a locale independent key from a predefined ResourceBundle for the
+ * keys defined in this class.
+ * <p>The constants in this class present a strongly typed enumeration
+ * of common object roles.  A public constructor for this class has been
+ * purposely omitted and applications should use one of the constants
+ * from this class.  If the constants in this class are not sufficient
+ * to describe the role of an object, a subclass should be generated
+ * from this class and it should provide constants in a similar manner.
+ *
+ */
+
+public abstract class AccessibleExtendedStateConstants extends AccessibleState {
+
+    /**
+     * Indicates a component is responsible for managing
+     * its subcomponents.
+     */
+    public static final AccessibleExtendedState MANAGES_DESCENDENTS
+            = new AccessibleExtendedState("managesDescendents");
+
+    public AccessibleExtendedStateConstants(String s) {
+        super(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/legacy/AccessBridgeLoader.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package com.sun.java.accessibility;
+
+@jdk.Exported(false)
+abstract class AccessBridgeLoader {
+
+    /**
+     * Load JavaAccessBridge.DLL (our native half)
+     */
+    static {
+        java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Object>() {
+                public Object run() {
+                    System.loadLibrary("JavaAccessBridge");
+                    return null;
+                }
+            }, null, new RuntimePermission("loadLibrary.JavaAccessBridge")
+        );
+    }
+
+    boolean useJAWT_DLL = false;
+
+    /**
+     * AccessBridgeLoader constructor
+     */
+    AccessBridgeLoader() {
+        String version = System.getProperty("java.version");
+        if (version != null)
+            useJAWT_DLL = (version.compareTo("1.4.1") >= 0);
+
+        // load JAWTAccessBridge.DLL on JDK 1.4.1 or later
+        if (useJAWT_DLL) {
+            // Note that we have to explicitly load JAWT.DLL
+            java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Object>() {
+                    public Object run() {
+                        System.loadLibrary("JAWT");
+                        System.loadLibrary("JAWTAccessBridge");
+                        return null;
+                    }
+                }, null, new RuntimePermission("loadLibrary.JAWT"),
+                         new RuntimePermission("loadLibrary.JAWTAccessBridge")
+            );
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/com/sun/java/accessibility/util/AWTEventMonitor.java	Tue Mar 31 18:39:00 2015 +0400
@@ -0,0 +1,1495 @@
+/*
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.java.accessibility.util;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.accessibility.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import sun.security.util.SecurityConstants.AWT;
+
+/**
+ * <P>The {@code AWTEventMonitor} implements a suite of listeners that are
+ * conditionally installed on every AWT component instance in the Java
+ * Virtual Machine.  The events captured by these listeners are made
+ * available through a unified set of listeners supported by {@code AWTEventMonitor}.
+ * With this, all the individual events on each of the AWT component
+ * instances are funneled into one set of listeners broken down by category
+ * (see {@link EventID} for the categories).
+ * <p>This class depends upon {@link EventQueueMonitor}, which provides the base
+ * level support for capturing the top-level containers as they are created.
+ */
+
+@jdk.Exported
+public class AWTEventMonitor {
+
+    static private boolean runningOnJDK1_4 = false;
+
+    /**
+     * The current component with keyboard focus.
+     *
+     * @see #getComponentWithFocus
+     *
+     * @deprecated This field is unused; to get the component with focus use the
+     * getComponentWithFocus method.
+     */
+    @Deprecated
+    static protected Component componentWithFocus = null;
+
+    static private Component componentWithFocus_private = null;
+
+    // Low-level listeners
+    /**
+     * The current list of registered ComponentListener classes.
+     *
+     * @see #addComponentListener
+     * @see #removeComponentListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected ComponentListener     componentListener     = null;
+
+    static private ComponentListener componentListener_private = null;
+
+    /**
+     * The current list of registered ContainerListener classes.
+     *
+     * @see #addContainerListener
+     * @see #removeContainerListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected ContainerListener     containerListener     = null;
+
+    static private ContainerListener containerListener_private = null;
+
+    /**
+     * The current list of registered FocusListener classes.
+     *
+     * @see #addFocusListener
+     * @see #removeFocusListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected FocusListener         focusListener         = null;
+
+    static private FocusListener focusListener_private = null;
+
+    /**
+     * The current list of registered KeyListener classes.
+     *
+     * @see #addKeyListener
+     * @see #removeKeyListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected KeyListener           keyListener           = null;
+
+    static private KeyListener keyListener_private = null;
+
+    /**
+     * The current list of registered MouseListener classes.
+     *
+     * @see #addMouseListener
+     * @see #removeMouseListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected MouseListener         mouseListener         = null;
+
+    static private MouseListener mouseListener_private = null;
+
+    /**
+     * The current list of registered MouseMotionListener classes.
+     *
+     * @see #addMouseMotionListener
+     * @see #removeMouseMotionListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected MouseMotionListener   mouseMotionListener   = null;
+
+    static private MouseMotionListener mouseMotionListener_private = null;
+
+    /**
+     * The current list of registered WindowListener classes.
+     *
+     * @see #addWindowListener
+     * @see #removeWindowListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected WindowListener        windowListener        = null;
+
+    static private WindowListener windowListener_private = null;
+
+
+    // Semantic listeners
+    /**
+     * The current list of registered ActionListener classes.
+     *
+     * @see #addActionListener
+     * @see #removeActionListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected ActionListener        actionListener        = null;
+
+    static private ActionListener actionListener_private = null;
+
+    /**
+     * The current list of registered AdjustmentListener classes.
+     *
+     * @see #addAdjustmentListener
+     * @see #removeAdjustmentListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected AdjustmentListener    adjustmentListener    = null;
+
+    static private AdjustmentListener adjustmentListener_private = null;
+
+    /**
+     * The current list of registered ItemListener classes.
+     *
+     * @see #addItemListener
+     * @see #removeItemListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected ItemListener          itemListener          = null;
+
+    static private ItemListener itemListener_private = null;
+
+    /**
+     * The current list of registered TextListener classes.
+     *
+     * @see #addTextListener
+     * @see #removeTextListener
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected TextListener          textListener          = null;
+
+    static private TextListener textListener_private = null;
+
+
+    /**
+     * The actual listener that is installed on the component instances.
+     * This listener calls the other registered listeners when an event
+     * occurs.  By doing things this way, the actual number of listeners
+     * installed on a component instance is drastically reduced.
+     *
+     * @deprecated This field is unused.
+     */
+    @Deprecated
+    static protected AWTEventsListener awtListener = new AWTEventsListener();
+
+    static private final AWTEventsListener awtListener_private = new AWTEventsListener();
+
+    /**
+     * Returns the component that currently has keyboard focus.  The return
+     * value can be null.
+     *
+     * @return the component that has keyboard focus
+     */
+    static public Component getComponentWithFocus() {
+        return componentWithFocus_private;
+    }
+
+    /*
+     * Check permissions
+     */
+    static private void checkInstallPermission() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(AWT.ALL_AWT_EVENTS_PERMISSION);
+        }
+    }
+
+    /**
+     * Adds the specified listener to receive all {@link EventID#COMPONENT COMPONENT}
+     * events on each component instance in the Java Virtual Machine as they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeComponentListener
+     */
+    static public void addComponentListener(ComponentListener l) {
+        if (componentListener_private == null) {
+            checkInstallPermission();
+            awtListener_private.installListeners(EventID.COMPONENT);
+        }
+        componentListener_private = AWTEventMulticaster.add(componentListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives
+     * {@link EventID#COMPONENT COMPONENT} events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addComponentListener
+     */
+    static public void removeComponentListener(ComponentListener l) {
+        componentListener_private = AWTEventMulticaster.remove(componentListener_private, l);
+        if (componentListener_private == null) {
+            awtListener_private.removeListeners(EventID.COMPONENT);
+        }
+    }
+
+    /**
+     * Adds the specified listener to receive all {@link EventID#CONTAINER CONTAINER}
+     * events on each component instance in the Java Virtual Machine as they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeContainerListener
+     */
+    static public void addContainerListener(ContainerListener l) {
+        containerListener_private = AWTEventMulticaster.add(containerListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives
+     * {@link EventID#CONTAINER CONTAINER} events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addContainerListener
+     */
+    static public void removeContainerListener(ContainerListener l) {
+        containerListener_private = AWTEventMulticaster.remove(containerListener_private, l);
+    }
+
+    /**
+     * Adds the specified listener to receive all {@link EventID#FOCUS FOCUS} events
+     * on each component instance in the Java Virtual Machine when they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeFocusListener
+     */
+    static public void addFocusListener(FocusListener l) {
+        focusListener_private = AWTEventMulticaster.add(focusListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives {@link EventID#FOCUS FOCUS}
+     * events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addFocusListener
+     */
+    static public void removeFocusListener(FocusListener l) {
+        focusListener_private = AWTEventMulticaster.remove(focusListener_private, l);
+    }
+
+    /**
+     * Adds the specified listener to receive all {@link EventID#KEY KEY} events on each
+     * component instance in the Java Virtual Machine when they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeKeyListener
+     */
+    static public void addKeyListener(KeyListener l) {
+        if (keyListener_private == null) {
+            checkInstallPermission();
+            awtListener_private.installListeners(EventID.KEY);
+        }
+        keyListener_private = AWTEventMulticaster.add(keyListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives {@link EventID#KEY KEY}
+     * events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addKeyListener
+     */
+    static public void removeKeyListener(KeyListener l) {
+        keyListener_private = AWTEventMulticaster.remove(keyListener_private, l);
+        if (keyListener_private == null)  {
+            awtListener_private.removeListeners(EventID.KEY);
+        }
+    }
+
+    /**
+     * Adds the specified listener to receive all {@link EventID#MOUSE MOUSE} events
+     * on each component instance in the Java Virtual Machine when they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeMouseListener
+     */
+    static public void addMouseListener(MouseListener l) {
+        if (mouseListener_private == null) {
+            checkInstallPermission();
+            awtListener_private.installListeners(EventID.MOUSE);
+        }
+        mouseListener_private = AWTEventMulticaster.add(mouseListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives
+     * {@link EventID#MOUSE MOUSE} events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addMouseListener
+     */
+    static public void removeMouseListener(MouseListener l) {
+        mouseListener_private = AWTEventMulticaster.remove(mouseListener_private, l);
+        if (mouseListener_private == null) {
+            awtListener_private.removeListeners(EventID.MOUSE);
+        }
+    }
+
+    /**
+     * Adds the specified listener to receive all mouse {@link EventID#MOTION MOTION}
+     * events on each component instance in the Java Virtual Machine when they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeMouseMotionListener
+     */
+    static public void addMouseMotionListener(MouseMotionListener l) {
+        if (mouseMotionListener_private == null) {
+            checkInstallPermission();
+            awtListener_private.installListeners(EventID.MOTION);
+        }
+        mouseMotionListener_private = AWTEventMulticaster.add(mouseMotionListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives
+     * {@link EventID#MOTION MOTION} events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addMouseMotionListener
+     */
+    static public void removeMouseMotionListener(MouseMotionListener l) {
+        mouseMotionListener_private = AWTEventMulticaster.remove(mouseMotionListener_private, l);
+        if (mouseMotionListener_private == null) {
+            awtListener_private.removeListeners(EventID.MOTION);
+        }
+    }
+
+    /**
+     * Adds the specified listener to receive all {@link EventID#WINDOW WINDOW}
+     * events on each component instance in the Java Virtual Machine when they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeWindowListener
+     */
+    static public void addWindowListener(WindowListener l) {
+        if (windowListener_private == null) {
+            checkInstallPermission();
+            awtListener_private.installListeners(EventID.WINDOW);
+        }
+        windowListener_private = AWTEventMulticaster.add(windowListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives
+     * {@link EventID#WINDOW WINDOW} events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addWindowListener
+     */
+    static public void removeWindowListener(WindowListener l) {
+        windowListener_private = AWTEventMulticaster.remove(windowListener_private, l);
+        if (windowListener_private == null) {
+            awtListener_private.removeListeners(EventID.WINDOW);
+        }
+    }
+
+    /**
+     * Adds the specified listener to receive all {@link EventID#ACTION ACTION}
+     * events on each component instance in the Java Virtual Machine when they occur.
+     * <P>Note: This listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeActionListener
+     */
+    static public void addActionListener(ActionListener l) {
+        if (actionListener_private == null) {
+            checkInstallPermission();
+            awtListener_private.installListeners(EventID.ACTION);
+        }
+        actionListener_private = AWTEventMulticaster.add(actionListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives
+     * {@link EventID#ACTION ACTION} events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addActionListener
+     */
+    static public void removeActionListener(ActionListener l) {
+        actionListener_private = AWTEventMulticaster.remove(actionListener_private, l);
+        if (actionListener_private == null) {
+            awtListener_private.removeListeners(EventID.ACTION);
+        }
+    }
+
+    /**
+     * Adds the specified listener to receive all
+     * {@link EventID#ADJUSTMENT ADJUSTMENT} events on each component instance
+     * in the Java Virtual Machine when they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeAdjustmentListener
+     */
+    static public void addAdjustmentListener(AdjustmentListener l) {
+        if (adjustmentListener_private == null) {
+            checkInstallPermission();
+            awtListener_private.installListeners(EventID.ADJUSTMENT);
+        }
+        adjustmentListener_private = AWTEventMulticaster.add(adjustmentListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives
+     * {@link EventID#ADJUSTMENT ADJUSTMENT} events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addAdjustmentListener
+     */
+    static public void removeAdjustmentListener(AdjustmentListener l) {
+        adjustmentListener_private = AWTEventMulticaster.remove(adjustmentListener_private, l);
+        if (adjustmentListener_private == null) {
+            awtListener_private.removeListeners(EventID.ADJUSTMENT);
+        }
+    }
+
+    /**
+     * Adds the specified listener to receive all {@link EventID#ITEM ITEM} events
+     * on each component instance in the Java Virtual Machine when they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeItemListener
+     */
+    static public void addItemListener(ItemListener l) {
+        if (itemListener_private == null) {
+            checkInstallPermission();
+            awtListener_private.installListeners(EventID.ITEM);
+        }
+        itemListener_private = AWTEventMulticaster.add(itemListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives {@link EventID#ITEM ITEM}
+     * events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addItemListener
+     */
+    static public void removeItemListener(ItemListener l) {
+        itemListener_private = AWTEventMulticaster.remove(itemListener_private, l);
+        if (itemListener_private == null) {
+            awtListener_private.removeListeners(EventID.ITEM);
+        }
+    }
+
+    /**
+     * Adds the specified listener to receive all {@link EventID#TEXT TEXT} events
+     * on each component instance in the Java Virtual Machine when they occur.
+     * <P>Note: this listener is automatically added to all component
+     * instances created after this method is called.  In addition, it
+     * is only added to component instances that support this listener type.
+     *
+     * @param l the listener to add
+     * @see #removeTextListener
+     */
+    static public void addTextListener(TextListener l) {
+        if (textListener_private == null) {
+            checkInstallPermission();
+            awtListener_private.installListeners(EventID.TEXT);
+        }
+        textListener_private = AWTEventMulticaster.add(textListener_private, l);
+    }
+
+    /**
+     * Removes the specified listener so it no longer receives {@link EventID#TEXT TEXT}
+     * events when they occur.
+     *
+     * @param l the listener to remove
+     * @see #addTextListener
+     */
+    static public void removeTextListener(TextListener l) {
+        textListener_private = AWTEventMulticaster.remove(textListener_private, l);
+        if (textListener_private == null) {
+            awtListener_private.removeListeners(EventID.TEXT);
+        }
+    }
+
+
+    /**
+     * AWTEventsListener is the class that does all the work for AWTEventMonitor.
+     * It is not intended for use by any other class except AWTEventMonitor.
+     *
+     */
+
+    static class AWTEventsListener implements TopLevelWindowListener,
+        ActionListener, AdjustmentListener, ComponentListener,
+        ContainerListener, FocusListener, ItemListener, KeyListener,
+        MouseListener, MouseMotionListener, TextListener, WindowListener,
+        ChangeListener {
+
+        /**
+         * internal variables for Action introspection
+         */
+        private java.lang.Class actionListeners[];
+        private java.lang.reflect.Method removeActionMethod;
+        private java.lang.reflect.Method addActionMethod;
+        private java.lang.Object actionArgs[];
+
+        /**
+         * internal variables for Item introspection
+         */
+        private java.lang.Class itemListeners[];
+        private java.lang.reflect.Method removeItemMethod;
+        private java.lang.reflect.Method addItemMethod;
+        private java.lang.Object itemArgs[];
+
+        /**
+         * internal variables for Text introspection
+         */
+        private java.lang.Class textListeners[];
+        private java.lang.reflect.Method removeTextMethod;
+        private java.lang.reflect.Method addTextMethod;
+        private java.lang.Object textArgs[];
+
+        /**
+         * internal variables for Window introspection
+         */
+        private java.lang.Class windowListeners[];
+        private java.lang.reflect.Method removeWindowMethod;
+        private java.lang.reflect.Method addWindowMethod;
+        private java.lang.Object windowArgs[];
+
+        /**
+         * Create a new instance of this class and install it on each component
+         * instance in the virtual machine that supports any of the currently
+         * registered listeners in AWTEventMonitor.  Also registers itself
+         * as a TopLevelWindowListener with EventQueueMonitor so it can
+         * automatically add new listeners to new components.
+         *
+         * @see EventQueueMonitor
+         * @see AWTEventMonitor
+         */
+        public AWTEventsListener() {
+            String version = System.getProperty("java.version");
+            if (version != null) {
+                runningOnJDK1_4 = (version.compareTo("1.4") >= 0);
+            }
+            initializeIntrospection();
+            installListeners();
+            if (runningOnJDK1_4) {
+                MenuSelectionManager.defaultManager().addChangeListener(this);
+            }
+            EventQueueMonitor.addTopLevelWindowListener(this);
+        }
+
+        /**
+         * Set up all of the variables needed for introspection
+         */
+        private boolean initializeIntrospection() {
+            try {
+                actionListeners = new java.lang.Class[1];
+                actionArgs = new java.lang.Object[1];
+                actionListeners[0] = Class.forName("java.awt.event.ActionListener");
+                actionArgs[0] = this;
+
+                itemListeners = new java.lang.Class[1];
+                itemArgs = new java.lang.Object[1];
+                itemListeners[0] = Class.forName("java.awt.event.ItemListener");
+                itemArgs[0] = this;
+
+                textListeners = new java.lang.Class[1];
+                textArgs = new java.lang.Object[1];
+                textListeners[0] = Class.forName("java.awt.event.TextListener");
+                textArgs[0] = this;
+
+                windowListeners = new java.lang.Class[1];
+                windowArgs = new java.lang.Object[1];
+                windowListeners[0] = Class.forName("java.awt.event.WindowListener");
+                windowArgs[0] = this;
+
+                return true;
+            } catch (ClassNotFoundException e) {
+                System.out.println("EXCEPTION - Class 'java.awt.event.*' not in CLASSPATH");
+                return false;
+            }
+        }
+
+        /**
+         * Installs all currently registered listeners on all components based
+         * upon the current topLevelWindows cached by EventQueueMonitor.
+         * @see EventQueueMonitor
+         * @see AWTEventMonitor
+         */
+        protected void installListeners() {
+            Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows();
+            if (topLevelWindows != null) {
+                for (int i = 0; i < topLevelWindows.length; i++) {
+                    installListeners(topLevelWindows[i]);
+                }
+            }
+        }
+
+        /**
+         * Installs listeners for the given event ID on all components based
+         * upon the current topLevelWindows cached by EventQueueMonitor.
+         * @see EventID
+         * @param eventID the event ID
+         */
+        protected void installListeners(int eventID) {
+            Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows();
+            if (topLevelWindows != null) {
+                for (int i = 0; i < topLevelWindows.length; i++) {
+                    installListeners(topLevelWindows[i], eventID);
+                }
+            }
+        }
+
+        /**
+         * Installs all currently registered listeners to just the component.
+         * @param c the component to add listeners to
+         */
+        protected void installListeners(Component c) {
+
+            // Container and focus listeners are always installed for our own use.
+            //
+            installListeners(c,EventID.CONTAINER);
+            installListeners(c,EventID.FOCUS);
+
+            // conditionally install low-level listeners
+            //
+            if (AWTEventMonitor.componentListener_private != null) {
+                installListeners(c,EventID.COMPONENT);
+            }
+            if (AWTEventMonitor.keyListener_private != null) {
+                installListeners(c,EventID.KEY);
+            }
+            if (AWTEventMonitor.mouseListener_private != null) {
+                installListeners(c,EventID.MOUSE);
+            }
+            if (AWTEventMonitor.mouseMotionListener_private != null) {
+                installListeners(c,EventID.MOTION);
+            }
+            if (AWTEventMonitor.windowListener_private != null) {
+                installListeners(c,EventID.WINDOW);
+            }
+
+            // conditionally install Semantic listeners
+            //
+            if (AWTEventMonitor.actionListener_private != null) {
+                installListeners(c,EventID.ACTION);
+            }
+            if (AWTEventMonitor.adjustmentListener_private != null) {
+                installListeners(c,EventID.ADJUSTMENT);
+            }
+            if (AWTEventMonitor.itemListener_private != null) {
+                installListeners(c,EventID.ITEM);
+            }
+            if (AWTEventMonitor.textListener_private != null) {
+                installListeners(c,EventID.TEXT);
+            }
+        }
+
+        public void stateChanged(ChangeEvent e) {
+            processFocusGained();
+        }
+
+        private void processFocusGained() {
+            Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
+            if (focusOwner == null) {
+                return;
+            }
+            MenuSelectionManager.defaultManager().removeChangeListener(this);
+            MenuSelectionManager.defaultManager().addChangeListener(this);
+
+            // Only menus and popup selections are handled by the JRootPane.
+            if (focusOwner instanceof JRootPane) {
+                MenuElement [] path =
+                    MenuSelectionManager.defaultManager().getSelectedPath();
+                if (path.length > 1) {
+                    Component penult = path[path.length-2].getComponent();
+                    Component last = path[path.length-1].getComponent();
+
+                    if (last instanceof JPopupMenu ||
+                        last instanceof JMenu) {
+                        // This is a popup with nothing in the popup
+                        // selected. The menu itself is selected.
+                        componentWithFocus_private = last;
+                    } else if (penult instanceof JPopupMenu) {
+                        // This is a popup with an item selected
+                        componentWithFocus_private = penult;
+                    }
+                }
+            } else {
+                // The focus owner has the selection.
+                componentWithFocus_private = focusOwner;
+            }
+        }
+
+        /**
+         * Installs the given listener on the component and any of its children.
+         * As a precaution, it always attempts to remove itself as a listener
+         * first so it's always guaranteed to have installed itself just once.
+         * @param c the component to add listeners to
+         * @param eventID the eventID to add listeners for
+         * @see EventID
+         */
+        protected void installListeners(Component c, int eventID) {
+
+            // install the appropriate listener hook into this component
+            //
+            switch (eventID) {
+
+            case EventID.ACTION:
+                try {
+                    removeActionMethod = c.getClass().getMethod(
+                        "removeActionListener", actionListeners);
+                    addActionMethod = c.getClass().getMethod(
+                        "addActionListener", actionListeners);
+                    try {
+                        removeActionMethod.invoke(c, actionArgs);
+                        addActionMethod.invoke(c, actionArgs);
+                    } catch (java.lang.reflect.InvocationTargetException e) {
+                        System.out.println("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        System.out.println("Exception: " + e.toString());
+                    }
+                } catch (NoSuchMethodException e) {
+                    // System.out.println("Exception: " + e.toString());
+                } catch (SecurityException e) {
+                    System.out.println("Exception: " + e.toString());
+                }
+                break;
+
+            case EventID.ADJUSTMENT:
+                if (c instanceof Adjustable) {
+                    ((Adjustable) c).removeAdjustmentListener(this);
+                    ((Adjustable) c).addAdjustmentListener(this);
+                }
+                break;
+
+            case EventID.COMPONENT:
+                c.removeComponentListener(this);
+                c.addComponentListener(this);
+                break;
+
+            case EventID.CONTAINER:
+                if (c instanceof Container) {
+                    ((Container) c).removeContainerListener(this);
+                    ((Container) c).addContainerListener(this);
+                }
+                break;
+
+            case EventID.FOCUS:
+                c.removeFocusListener(this);
+                c.addFocusListener(this);
+
+                if (runningOnJDK1_4) {
+                    processFocusGained();
+
+                } else {        // not runningOnJDK1_4
+                    if ((c != componentWithFocus_private) && c.hasFocus()) {
+                        componentWithFocus_private = c;
+                    }
+                }
+                break;
+
+            case EventID.ITEM:
+                try {
+                    removeItemMethod = c.getClass().getMethod(
+                        "removeItemListener", itemListeners);
+                    addItemMethod = c.getClass().getMethod(
+                        "addItemListener", itemListeners);
+                    try {
+                        removeItemMethod.invoke(c, itemArgs);
+                        addItemMethod.invoke(c, itemArgs);
+                    } catch (java.lang.reflect.InvocationTargetException e) {
+                        System.out.println("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        System.out.println("Exception: " + e.toString());
+                    }
+                } catch (NoSuchMethodException e) {
+                    // System.out.println("Exception: " + e.toString());
+                } catch (SecurityException e) {
+                    System.out.println("Exception: " + e.toString());
+                }
+                // [PK] CheckboxMenuItem isn't a component but it does
+                // implement Interface ItemSelectable!!
+                // if (c instanceof CheckboxMenuItem) {
+                //     ((CheckboxMenuItem) c).removeItemListener(this);
+                //     ((CheckboxMenuItem) c).addItemListener(this);
+                break;
+
+            case EventID.KEY:
+                c.removeKeyListener(this);
+                c.addKeyListener(this);
+                break;
+
+            case EventID.MOUSE:
+                c.removeMouseListener(this);
+                c.addMouseListener(this);
+                break;
+
+            case EventID.MOTION:
+                c.removeMouseMotionListener(this);
+                c.addMouseMotionListener(this);
+                break;
+
+            case EventID.TEXT:
+                try {
+                    removeTextMethod = c.getClass().getMethod(
+                        "removeTextListener", textListeners);
+                    addTextMethod = c.getClass().getMethod(
+                        "addTextListener", textListeners);
+                    try {
+                        removeTextMethod.invoke(c, textArgs);
+                        addTextMethod.invoke(c, textArgs);
+                    } catch (java.lang.reflect.InvocationTargetException e) {
+                        System.out.println("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        System.out.println("Exception: " + e.toString());
+                    }
+                } catch (NoSuchMethodException e) {
+                    // System.out.println("Exception: " + e.toString());
+                } catch (SecurityException e) {
+                    System.out.println("Exception: " + e.toString());
+                }
+                break;
+
+            case EventID.WINDOW:
+                try {
+                    removeWindowMethod = c.getClass().getMethod(
+                        "removeWindowListener", windowListeners);
+                    addWindowMethod = c.getClass().getMethod(
+                        "addWindowListener", windowListeners);
+                    try {
+                        removeWindowMethod.invoke(c, windowArgs);
+                        addWindowMethod.invoke(c, windowArgs);
+                    } catch (java.lang.reflect.InvocationTargetException e) {
+                        System.out.println("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        System.out.println("Exception: " + e.toString());
+                    }
+                } catch (NoSuchMethodException e) {
+                    // System.out.println("Exception: " + e.toString());
+                } catch (SecurityException e) {
+                    System.out.println("Exception: " + e.toString());
+                }
+                break;
+
+            // Don't bother recursing the children if this isn't going to
+            // accomplish anything.
+            //
+            default:
+                return;
+            }
+
+            // if this component is a container, recurse through children
+            //
+            if (c instanceof Container) {
+                int count = ((Container) c).getComponentCount();
+                for (int i = 0; i < count; i++) {
+                    installListeners(((Container) c).getComponent(i), eventID);
+                }
+            }
+        }
+
+        /**
+         * Removes all listeners for the given event ID on all components based
+         * upon the topLevelWindows cached by EventQueueMonitor.
+         * @param eventID the event ID
+         * @see EventID
+         */
+        protected void removeListeners(int eventID) {
+            Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows();
+            if (topLevelWindows != null) {
+                for (int i = 0; i < topLevelWindows.length; i++) {
+                    removeListeners(topLevelWindows[i], eventID);
+                }
+            }
+        }
+
+        /**
+         * Removes all listeners for the given component and all its children.
+         * @param c the component
+         */
+        protected void removeListeners(Component c) {
+
+            // conditionally remove low-level listeners
+            //
+            if (AWTEventMonitor.componentListener_private != null) {
+                removeListeners(c,EventID.COMPONENT);
+            }
+            if (AWTEventMonitor.keyListener_private != null) {
+                removeListeners(c,EventID.KEY);
+            }
+            if (AWTEventMonitor.mouseListener_private != null) {
+                removeListeners(c,EventID.MOUSE);
+            }
+            if (AWTEventMonitor.mouseMotionListener_private != null) {
+                removeListeners(c,EventID.MOTION);
+            }
+            if (AWTEventMonitor.windowListener_private != null) {
+                removeListeners(c,EventID.WINDOW);
+            }
+
+            // Remove semantic listeners
+            //
+            if (AWTEventMonitor.actionListener_private != null) {
+                removeListeners(c,EventID.ACTION);
+            }
+            if (AWTEventMonitor.adjustmentListener_private != null) {
+                removeListeners(c,EventID.ADJUSTMENT);
+            }
+            if (AWTEventMonitor.itemListener_private != null) {
+                removeListeners(c,EventID.ITEM);
+            }
+            if (AWTEventMonitor.textListener_private != null) {
+                removeListeners(c,EventID.TEXT);
+            }
+        }
+
+        /**
+         * Removes all listeners for the event ID from the component and all
+         * of its children.
+         * @param c the component to remove listeners from
+         * @see EventID
+         */
+        protected void removeListeners(Component c, int eventID) {
+
+            // remove the appropriate listener hook into this component
+            //
+            switch (eventID) {
+
+            case EventID.ACTION:
+                try {
+                    removeActionMethod = c.getClass().getMethod(
+                        "removeActionListener",
+                        actionListeners);
+                    try {
+                        removeActionMethod.invoke(c, actionArgs);
+                    } catch (java.lang.reflect.InvocationTargetException e) {
+                        System.out.println("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        System.out.println("Exception: " + e.toString());
+                    }
+                } catch (NoSuchMethodException e) {
+                    // System.out.println("Exception: " + e.toString());
+                } catch (SecurityException e) {
+                    System.out.println("Exception: " + e.toString());
+                }
+                break;
+
+            case EventID.ADJUSTMENT:
+                if (c instanceof Adjustable) {
+                    ((Adjustable) c).removeAdjustmentListener(this);
+                }
+                break;
+
+            case EventID.COMPONENT:
+                c.removeComponentListener(this);
+                break;
+
+            // Never remove these because we're always interested in them
+            // for our own use.
+            //case EventID.CONTAINER:
+            //    if (c instanceof Container) {
+            //        ((Container) c).removeContainerListener(this);
+            //    }
+            //    break;
+            //
+            //case EventID.FOCUS:
+            //    c.removeFocusListener(this);
+            //    break;
+
+            case EventID.ITEM:
+                try {
+                    removeItemMethod = c.getClass().getMethod(
+                        "removeItemListener", itemListeners);
+                    try {
+                        removeItemMethod.invoke(c, itemArgs);
+                    } catch (java.lang.reflect.InvocationTargetException e) {
+                        System.out.println("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        System.out.println("Exception: " + e.toString());
+                    }
+                } catch (NoSuchMethodException e) {
+                    // System.out.println("Exception: " + e.toString());
+                } catch (SecurityException e) {
+                    System.out.println("Exception: " + e.toString());
+                }
+                // [PK] CheckboxMenuItem isn't a component but it does
+                // implement Interface ItemSelectable!!
+                // if (c instanceof CheckboxMenuItem) {
+                //     ((CheckboxMenuItem) c).removeItemListener(this);
+                break;
+
+            case EventID.KEY:
+                c.removeKeyListener(this);
+                break;
+
+            case EventID.MOUSE:
+                c.removeMouseListener(this);
+                break;
+
+            case EventID.MOTION:
+                c.removeMouseMotionListener(this);
+                break;
+
+            case EventID.TEXT:
+                try {
+                    removeTextMethod = c.getClass().getMethod(
+                        "removeTextListener", textListeners);
+                    try {
+                        removeTextMethod.invoke(c, textArgs);
+                    } catch (java.lang.reflect.InvocationTargetException e) {
+                        System.out.println("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        System.out.println("Exception: " + e.toString());
+                    }
+                } catch (NoSuchMethodException e) {
+                    // System.out.println("Exception: " + e.toString());
+                } catch (SecurityException e) {
+                    System.out.println("Exception: " + e.toString());
+                }
+                break;
+
+            case EventID.WINDOW:
+                try {
+                    removeWindowMethod = c.getClass().getMethod(
+                        "removeWindowListener", windowListeners);
+                    try {
+                        removeWindowMethod.invoke(c, windowArgs);
+                    } catch (java.lang.reflect.InvocationTargetException e) {
+                        System.out.println("Exception: " + e.toString());
+                    } catch (IllegalAccessException e) {
+                        System.out.println("Exception: " + e.toString());
+                    }
+                } catch (NoSuchMethodException e) {
+                    // System.out.println("Exception: " + e.toString());
+                } catch (SecurityException e) {
+                    System.out.println("Exception: " + e.toString());
+                }
+                break;
+
+            default:
+                return;
+            }
+
+            if (c instanceof Container) {
+                int count = ((Container) c).getComponentCount();
+                for (int i = 0; i < count; i++) {
+                    removeListeners(((Container) c).getComponent(i), eventID);
+                }
+            }
+        }
+
+        /********************************************************************/
+        /*                                                                  */
+        /* Listener Interface Methods                                       */
+        /*                                                                  */
+        /********************************************************************/
+
+        /* TopLevelWindow Methods ***************************************/
+
+        /**
+         * Called when top level window is created.
+         * @see EventQueueMonitor
+         * @see EventQueueMonitor#addTopLevelWindowListener
+         */
+        public void topLevelWindowCreated(Window w) {
+            installListeners(w);
+        }
+
+        /**
+         * Called when top level window is destroyed.
+         * @see EventQueueMonitor
+         * @see EventQueueMonitor#addTopLevelWindowListener
+         */
+        public void topLevelWindowDestroyed(Window w) {
+        }
+
+        /* ActionListener Methods ***************************************/
+
+        /**
+         * Called when an action is performed.
+         * @see AWTEventMonitor#addActionListener
+         */
+        public void actionPerformed(ActionEvent e) {
+            if (AWTEventMonitor.actionListener_private != null) {
+                AWTEventMonitor.actionListener_private.actionPerformed(e);
+            }
+        }
+
+        /* AdjustmentListener Methods ***********************************/
+
+        /**
+         * Called when an adjustment is made.
+         * @see AWTEventMonitor#addAdjustmentListener
+         */
+        public void adjustmentValueChanged(AdjustmentEvent e) {
+            if (AWTEventMonitor.adjustmentListener_private != null) {
+                AWTEventMonitor.adjustmentListener_private.adjustmentValueChanged(e);
+            }
+        }
+
+        /* ComponentListener Methods ************************************/
+
+        /**
+         * Called when a component is hidden.
+         * @see AWTEventMonitor#addComponentListener
+         */
+        public void componentHidden(ComponentEvent e) {
+            if (AWTEventMonitor.componentListener_private != null) {
+                AWTEventMonitor.componentListener_private.componentHidden(e);
+            }
+        }
+
+        /**
+         * Called when a component is moved.
+         * @see AWTEventMonitor#addComponentListener
+         */
+        public void componentMoved(ComponentEvent e) {
+            if (AWTEventMonitor.componentListener_private != null) {
+                AWTEventMonitor.componentListener_private.componentMoved(e);
+            }
+        }
+
+        /**
+         * Called when a component is resized.
+         * @see AWTEventMonitor#addComponentListener
+         */
+        public void componentResized(ComponentEvent e) {
+            if (AWTEventMonitor.componentListener_private != null) {
+                AWTEventMonitor.componentListener_private.componentResized(e);
+            }
+        }
+
+        /**
+         * Called when a component is shown.
+         * @see AWTEventMonitor#addComponentListener
+         */
+        public void componentShown(ComponentEvent e) {
+            if (AWTEventMonitor.componentListener_private != null) {
+                AWTEventMonitor.componentListener_private.componentShown(e);
+            }
+        }
+
+        /* ContainerListener Methods ************************************/
+
+        /**
+         * Called when a component is added to a container.
+         * @see AWTEventMonitor#addContainerListener
+         */
+        public void componentAdded(ContainerEvent e) {
+            installListeners(e.getChild());
+            if (AWTEventMonitor.containerListener_private != null) {
+                AWTEventMonitor.containerListener_private.componentAdded(e);
+            }
+        }
+
+        /**
+         * Called when a component is removed from a container.
+         * @see AWTEventMonitor#addContainerListener
+         */
+        public void componentRemoved(ContainerEvent e) {
+            removeListeners(e.getChild());
+            if (AWTEventMonitor.containerListener_private != null) {
+                AWTEventMonitor.containerListener_private.componentRemoved(e);
+            }
+        }
+
+        /* FocusListener Methods ****************************************/
+
+        /**
+         * Called when a component gains keyboard focus.
+         * @see AWTEventMonitor#addFocusListener
+         */
+        public void focusGained(FocusEvent e) {
+            AWTEventMonitor.componentWithFocus_private = (Component) e.getSource();
+            if (AWTEventMonitor.focusListener_private != null) {
+                AWTEventMonitor.focusListener_private.focusGained(e);
+            }
+        }
+
+        /**
+         * Called when a component loses keyboard focus.
+         * @see AWTEventMonitor#addFocusListener
+         */
+        public void focusLost(FocusEvent e) {
+            AWTEventMonitor.componentWithFocus_private = null;
+            if (AWTEventMonitor.focusListener_private != null) {
+                AWTEventMonitor.focusListener_private.focusLost(e);
+            }
+        }
+
+        /* ItemListener Methods *****************************************/
+
+        /**
+         * Called when an item's state changes.
+         * @see AWTEventMonitor#addItemListener
+         */
+        public void itemStateChanged(ItemEvent e) {
+            if (AWTEventMonitor.itemListener_private != null) {
+                AWTEventMonitor.itemListener_private.itemStateChanged(e);
+            }
+        }
+
+        /* KeyListener Methods ******************************************/
+
+        /**
+         * Called when a key is pressed.
+         * @see AWTEventMonitor#addKeyListener
+         */
+        public void keyPressed(KeyEvent e) {
+            if (AWTEventMonitor.keyListener_private != null) {
+                AWTEventMonitor.keyListener_private.keyPressed(e);
+            }
+        }