如何选择AWT-EventQueue线程,当有多个线程

时间:2015-12-11 15:38:05

标签: java java-native-interface event-dispatch-thread oracleforms

我使用DLL注入和一些jni技巧成功地在运行的Oracle Forms应用程序中注入了我自己的Java代码。 (Windows 7,32位,Oracle Forms 11,JRE Java 8)

我能够遍历组件树并在一些基本Java对象中查询和设置值,例如来自类oracle.forms.ui.VTextField

的对象

我在尝试模拟用户点击oracle.apps.fnd.ui.Button

时遇到困难

我尝试了两件事:

  1. 调用simulatePush
  2. AbstractButton方法
  3. 调用activate
  4. PushButton方法

    (这两个类位于Button的类层次结构中)

    结果相同:  1.首先,它工作正常:当按钮是“搜索”按钮时,搜索完成并显示结果。  2.然后,它立即打破应用程序,弹出一个说FRM-92100 Your connection to the Server was interrupted

    从那里,应用程序挂起。

    更新 似乎导致与服务器断开连接的错误是:

      

    java.lang.SecurityException:此KeyboardFocusManager不是   安装在当前线程的上下文中   java.awt.KeyboardFocusManager.checkCurrentKFMSecurity(未知来源)     at java.awt.KeyboardFocusManager.getGlobalFocusOwner(Unknown Source)     在   java.awt.KeyboardFocusManager.processSynchronousLightweightTransfer(未知   来源)at   sun.awt.windows.WComponentPeer.processSynchronousLightweightTransfer(母语   方法)at sun.awt.windows.WComponentPeer.requestFocus(未知   来自)java.awt.Component.requestFocusHelper(未知来源)at   java.awt.Component.requestFocusHelper(未知来源)at   java.awt.Component.requestFocus(未知来源)at   oracle.forms.handler.UICommon.updateFocus(未知来源)at   oracle.forms.handler.UICommon.setFVP(未知来源)at   oracle.forms.handler.UICommon.setFVP(未知来源)at   oracle.forms.handler.UICommon.onUpdate(未知来源)at   oracle.forms.handler.ComponentItem.onUpdate(未知来源)at   oracle.forms.handler.JavaContainer.onUpdate(未知来源)at   oracle.forms.handler.UICommon.onUpdate(未知来源)at   oracle.forms.engine.Runform.onUpdateHandler(未知来源)at   oracle.forms.engine.Runform.processMessage(未知来源)at   oracle.forms.engine.Runform.processSet(未知来源)at   oracle.forms.engine.Runform.onMessageReal(未知来源)at   oracle.forms.engine.Runform.onMessage(未知来源)at   oracle.forms.engine.Runform.processEventEnd(未知来源)at   oracle.ewt.lwAWT.LWComponent.redispatchEvent(未知来源)at   oracle.ewt.lwAWT.LWComponent.processEvent(未知来源)at   oracle.ewt.button.PushButton.activate(未知来源)at   sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at   sun.reflect.NativeMethodAccessorImpl.invoke(未知来源)at   sun.reflect.DelegatingMethodAccessorImpl.invoke(未知来源)at   java.lang.reflect.Method.invoke(未知来源)at   CustomAWT.run(CustomAWT.java:34)at   java.awt.event.InvocationEvent.dispatch(未知来源)at   java.awt.EventQueue.dispatchEventImpl(未知来源)at   java.awt.EventQueue.access $ 400(未知来源)at   java.awt.EventQueue $ 2.run(未知来源)at   java.awt.EventQueue $ 2.run(未知来源)at   java.security.AccessController.doPrivileged(Native Method)at   java.security.AccessControlContext $ 1.doIntersectionPrivilege(未知   来自)java.awt.EventQueue.dispatchEvent(未知来源)at   java.awt.EventDispatchThread.pumpOneEventForFilters(未知来源)     at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)     在java.awt.EventDispatchThread.pumpEventsForHierarchy(未知   来自java.awt.EventDispatchThread.pumpEvents(未知来源)     at java.awt.EventDispatchThread.pumpEvents(Unknown Source)at   java.awt.EventDispatchThread.run(未知来源)

    我的代码在这里:CustomAWT.run(CustomAWT.java:34)并使用invokeLater进行调用。问题可能是:在调用oracle.ewt.button.PushButton.activate方法时,我不在正确的EDT中。

    在Java控制台中使用“列出线程”,我得到了:

    Dump thread list ...
    Group main,ac=30,agc=2,pri=10
        main,5,alive
        traceMsgQueueThread,5,alive,daemon
        Timer-0,5,alive
        Java Plug-In Pipe Worker Thread (Client-Side),5,alive,daemon
        AWT-Shutdown,5,alive
        AWT-Windows,6,alive,daemon
        AWT-EventQueue-0,6,alive
        SysExecutionTheadCreator,5,alive,daemon
        CacheMemoryCleanUpThread,5,alive,daemon
        CacheCleanUpThread,5,alive,daemon
        Browser Side Object Cleanup Thread,5,alive
        JVM[id=0]-Heartbeat,5,alive,daemon
        Windows Tray Icon Thread,5,alive
        Thread-13,5,alive
    Group Plugin Thread Group,ac=3,agc=0,pri=10
        AWT-EventQueue-1,6,alive
        TimerQueue,5,alive,daemon
        ConsoleWriterThread,6,alive,daemon
    Group http://xxxx.xxxx.xxxxx.xx:8001/OA_JAVA/-threadGroup,ac=13,agc=0,pri=4
        Applet 1 LiveConnect Worker Thread,4,alive
        AWT-EventQueue-2,4,alive
        thread applet-oracle/apps/fnd/formsClient/FormsLauncher.class-1,4,alive
        Applet 2 LiveConnect Worker Thread,4,alive
        thread applet-oracle.forms.engine.Main-2,4,alive
        Forms-StreamMessageReader,4,alive
        Forms-StreamMessageWriter,4,alive
        HeartBeat,4,alive
        Busy indicator,1,alive,daemon
        TaskScheduler timer,4,alive
        CursorIdler,4,alive
        Thread-14,4,alive
        Flush Queue,4,alive
    Done.
    

    所以,有三个 AWT-EventQueue个主题...现在问题:如何查询/检索正确的主题,以及如何将Runnable传递给{ {1}}在“好线程”中运行(我想好的是最后一个(invokeLater

5 个答案:

答案 0 :(得分:1)

经过大量实验和使用EventQueueThreadGroup等关键字进行Google搜索后,我终于找到了解决方案(在 Works For Me 类别中,请注意)。

我使用sun.awt.AppContext类。一些文档和来源here(grepcode.com)

  1. 使用AppContext方法获取正在运行的getAppContexts的集合。
  2. 对于每个已检索的AppContext,请使用ThreadGroup方法获取getThreadGroup
  3. 使用ThreadGroup对象,使用getName方法。
  4. 当Thread Group的名称以Forms应用程序的http:地址开头时,使用Object sun.awt.AppContext.EVENT_QUEUE_KEY方法检索get属性,其密钥名称为AppContext。 }}。
  5. 检索到的对象是EventQueue。创建java.awt.event.InvocationEvent对象,将Runnable传递给CTOR,并使用postEvent的{​​{1}}方法。
  6. 您的EventQueue方法将在正确的主题中执行。
  7. 说明:

    • 这个答案是特定的,适用于我,通过Internet Explorer链接启动的Oracle Forms Application解决方案,并在java.exe进程中运行。在这种情况下,3个主题组如问题所示:runmainPlugin Thread Group您的里程可能会有所不同。
    • 如果你不使用全反射,而是导入http://xxxx.xxxx.xxxxx.xx:8001/OA_JAVA/-threadGroup,编译器可能会以sun.awt.AppContext的形式发出警告,但这不是很酷,但我会活下去就此而言,暂时。
    • warning: sun.awt.AppContext is Sun proprietary API and may be removed in a future release方法中,我使用run的{​​{1}}方法测试了正常。
    • 此处模拟的方法是simulatePush。对于oracle.ewt.lwAWT.AbstractButtoninvokeLater调用需要更多代码。查看invokeAndWait类的一些来源,作为起点。

答案 1 :(得分:1)

要获得正确的EDT线程,无论您的线程组如何,都可以使用SunToolkit.targetToAppContext(Object target),对于参数,您可以为其提供要执行的AWT组件。示例source

然后使用EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);

获取EventQueue

最后,使用runnable创建一个新的InvocationEvent并在EQ上调用postEvent。

答案 2 :(得分:0)

您应该能够扩展VButton类 您的类定义应该类似于:

init

然后你需要一个public void init(IHandler handler) { m_handler = handler; super.init(handler); addMouseListener(new ButtonMouseAdapter()); addFocusListener(this); } 类,如:

public void focusGained(FocusEvent e)
     {
         if (e.getComponent() == this)
         {
             // put the focus on the component
             e.getComponent().requestFocus();
             bFocus = true ;
         }
     }

  public void focusLost(FocusEvent e)
     {     
       bFocus = false ;
     }

  /**
   * Private class to handle user mouse actions
   */
  class ButtonMouseAdapter extends MouseAdapter
  {
    /**
     * User moved the mouse over the button
     */
    public void mouseEntered(MouseEvent me)
    {
      bFocus=true ;
      mouseON();
    }

    /**
     * User moved the mouse out of the button
     */
    public void mouseExited(MouseEvent me)
    {
      bFocus=false ;
      mouseOFF();
    }
    /**
     * User moved the mouse out of the button
     */
    public void mousePressed(MouseEvent me)
    {
      bPressed = true ;
    }
    /**
     * User moved the mouse out of the button
     */
    public void mouseReleased(MouseEvent me)
    {
      bPressed = false ;
    }

  }

然后你需要实现监听器并在其中做一些事情:

.movie.mp4{
	border:5px solid red;
			}

我希望此代码适合您。

此致

答案 3 :(得分:0)

  

我使用DLL注入和一些jni技巧成功地在运行的Oracle Forms应用程序中注入了我自己的Java代码。

这是真正的问题,IMO。

你正在遭受目标固定,这意味着你,程序员,对于他们想要什么样的解决方案有一个固定的心理想法,这会使你蒙蔽其他一切。目标固定导致飞机失事,因为即使是经验丰富且智能的飞行员(事实上整个驾驶舱!)已经变得如此注重一个问题中的一个问题,他们让其他灾难一直在滑落。

摆脱这种心态。

您想要的解决方案无法解决问题,请继续尝试其他方法。就像@ nightfox79已经提供给你的明智选项一样。

你正试图规避一个复杂的对象类,当你应该简单地扩展你试图破解的现有类时。这是OOP发展的全部基础。

DLL / JNI Trickery没有合理的解决方案,IMO。

我很遗憾必须维护和修复任何基于DLL / JNI hack的代码解决方案。这就是疯狂。

invokeLater()未在正确的EDT下运行的理论可能是错误的。根据文档,invokeLater()总是将您请求的代码排队到AWT事件处理程序的挂起代码列表中,这正是它应该的位置。试图绕过这几乎肯定会导致可怕的问题。 invokeLater()的全部目的是在您调用它的EDT中推迟重量级处理,并在稍后的完全相同的线程上运行它。它是invokeLater()中的一个错误,如果没有,IMO。

但是,如果您想检查正在运行的线程代码,那么我所知道的唯一测试是在您的代码中使用它;

if (SwingUtilities.isEventDispatchThread())
{
    System.err.println("Is running on EDT");
}
else
{
    System.err.println("Is not running on EDT");
}

答案 4 :(得分:0)

我也试图在正在运行的Oracle Forms应用程序中推送我的Java代码,基本上我正在尝试通过UI自动化oracle表单流,从上面评论看起来你做得非常出色,你能指导我吗?这个,我创建了java代理,问题是如何在运行在web中运行的oracle表单applet中注入它。第二个问题是在我的java代理中处理premain方法时,我应该使用什么来进行oracle表单对象识别,普通小程序我正在使用Toolkit tk = Toolkit.getDefaultToolkit();然后我正在收听来自windows的调度事件。请指导我,我真的很难自动化这个