2015-12-11 16 views
10

Ho inserito correttamente il mio codice Java in un'applicazione Oracle Forms in esecuzione, utilizzando DLL Injection e alcuni jni trickery. (Windows 7, 32 bit, Oracle Forms 11, Java JRE 8)Come scegliere un thread AWT-EventQueue, quando ce ne sono diversi

sono in grado di attraversare l'albero di componenti e per interrogare e impostare i valori in alcuni oggetti Java di base, come quelli dalla classe oracle.forms.ui.VTextField

sono bloccato quando si cerca di simulare clic dell'utente su un oracle.apps.fnd.ui.Button

ho provato 2 cose:

  1. chiamata al metodo della classe di AbstractButton
  2. simulatePush
  3. chiamata al metodo della classe PushButton

(le 2 classi sono nella gerarchia delle classi per Button) activate

I risultati sono stati identici: 1. In un primo momento, funziona benissimo: quando il pulsante è un Pulsante "Cerca", la ricerca viene eseguita e vengono visualizzati i risultati. 2. Quindi, interrompe immediatamente l'applicazione, con un pop-up che dice FRM-92100 Your connection to the Server was interrupted.

Da lì, l'applicazione è bloccata.

Aggiornamento: Sembra che l'errore che causa una disconnessione dal server è:

java.lang.SecurityException: questo non è KeyboardFocusManager installata nel contesto del thread corrente java. awt.KeyboardFocusManager.checkCurrentKFMSecurity (fonte sconosciuta) a java.awt.KeyboardFocusManager.getGlobalFocusOwner (fonte sconosciuta) a java.awt.KeyboardFocusManager.processSynchronousLightweightTransfer (Sconosciuto Source) a sun.awt.windows.WComponentPeer.processSynchronousLightweightTransfer (Native Method) a sun.awt.windows.WComponentPeer.requestFocus (Sconosciuto Source) a java.awt.Component.requestFocusHelper (Origine Sconosciuta) A java.awt.Component .requestFocusHelper (Origine sconosciuta) a java.awt.Component.requestFocus (Origine sconosciuta) a oracle.forms.handler.UICommon.updateFocus (Origine sconosciuta) a oracle.forms.handler.UICommon.setFVP (Origine sconosciuta) a oracle.forms.handler.UICommon.setFVP (Fonte sconosciuta) a oracle.forms.handler.UICommon.onUpdate (Origine sconosciuta) a oracle.forms.handler.ComponentItem.onUpdate (Origine sconosciuta) a oracle.forms. handler.JavaContaine r.onUpdate (sorgente sconosciuta) a oracle.forms.handler.UICommon.onUpdate (sorgente sconosciuta) a oracle.forms.engine.Runform.onUpdateHandler (sorgente sconosciuta) a oracle.forms.engine.Runform.processMessage (sconosciuto fonte) a oracle.forms.engine.Runform.processSet (Origine sconosciuta) a oracle.forms.engine.Runform.onMessageReal (Origine sconosciuta) a oracle.forms.engine.Runform.onMessage (Origine sconosciuta) a Oracle .forms.engine.Runform.processEventEnd (sorgente sconosciuta) a oracle.ewt.lwAWT.LWComponent.redispatchEvent (Origine Sconosciuta) A oracle.ewt.lwAWT.LWComponent.processEvent (Origine Sconosciuta) A oracle.ewt.button.PushButton.activate (Origine Sconosciuta) A sun.reflect.NativeMethodAccessorImpl.invoke0 (metodo natale) a sun.reflect.NativeMethodAccessorImpl.invoke (Origine sconosciuta) a sun.reflect.DelegatingMethodAccessorImpl.invoke (Origine sconosciuta) a java.lang.reflect.Method.invoke (Origine sconosciuta) a CustomAWT.run (CustomAWT.java:34) a java.awt.event.InvocationEvent.dispatch (Origine sconosciuta) a java.awt.EventQueue.dispatchEventImpl (Origine sconosciuta) a java.awt.EventQueue.access $ 400 (Fonte sconosciuta) a java.awt.EventQueue $ 2.run (fonte sconosciuta) a java.awt.EventQueue $ 2.run (Fonte sconosciuta) a java.security.AccessController.doPrivileged (metodo natale) a java.security.AccessControlContext $ 1.doIntersectionPrivilege (Sconosciuto Source) a java.awt.EventQueue.dispatchEvent (Origine sconosciuta) a java.awt.EventDispatchThread.pumpOneEventForFilters (fonte sconosciuta) a java.awt.EventDispatchThread.pumpEventsForFilter (fonte sconosciuta) a java.awt.EventDispatchThread.pumpEventsForHierarchy (sconosciuto source) a java.awt.EventDispatchThread. pumpEvents (sorgente sconosciuta) a java.awt.EventDispatchThread.pumpEvents (sorgente sconosciuta) a java.awt.EventDispatchThread.run (sorgente sconosciuta)

Il mio codice è qui: CustomAWT.run(CustomAWT.java:34) e viene chiamato con invokeLater. Il problema è probabilmente: quando si chiama il metodo oracle.ewt.button.PushButton.activate, NON sono nell'EDT corretto.

Utilizzando "Elenco Threads" nella console Java, ho ottenuto:

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. 

Quindi, non v'è TREAWT-EventQueue discussioni ... La domanda è ora: come Query/Retrieve quella giusta, e come fare il Runnable passato a invokeLater per l'esecuzione in "Good filo" (immagino che quello buono è l'ultimo (AWT-EventQueue-2)

+0

Hai provato con il parametro applet 'separatedFrame =" True "? – dan

+0

@dan Non ho modo di cambiare nulla sul server. Non sono sicuro di capire cosa stai suggerendo. L'applicazione Oracle Forms (Oracle Application eBusiness Center) è già in esecuzione come finestra principale, figlio del Window Desktop. – manuell

risposta

1

Dopo un sacco di sperimentazione e le ricerche di Google con parole chiave come EventQueue e ThreadGroup ho finalmente trovato una soluzione (nei funziona per me categoria, sia chiaro).

Uso la classe sun.awt.AppContext. Alcuni documentazione e fonti here (grepcode.com)

  1. ottenere una raccolta di esecuzione AppContext 's utilizzando il metodo getAppContexts.
  2. Per ogni recupero AppContext, ottenere il suo ThreadGroup utilizzando il metodo getThreadGroup.
  3. Con l'oggetto ThreadGroup, utilizzare il metodo getName.
  4. Quando il nome del Thread Group inizia con l'http: indirizzo dell'applicazione Forms, recuperare la proprietà Object con il nome chiave sun.awt.AppContext.EVENT_QUEUE_KEY, utilizzando il metodo get di AppContext.
  5. L'oggetto recuperato è un EventQueue. Creare un oggetto java.awt.event.InvocationEvent, passando il Runnable al CTOR e utilizzare il metodo postEvent di EventQueue.
  6. Il tuo metodo run verrà eseguito nel thread corretto.

Osservazione:

  • Questa risposta è uno specifico, funziona per me, soluzione per Oracle Forms Application lanciato tramite un collegamento a Internet Explorer, e in esecuzione in un processo java.exe. In questa situazione, i 3 gruppi di thread sono come mostrato nella domanda: main, Plugin Thread Group e http://xxxx.xxxx.xxxxx.xx:8001/OA_JAVA/-threadGroup La tua situazione potrebbe variare.
  • Se non si utilizza il riflesso completo, ma invece si importa sun.awt.AppContext, il compilatore può emettere avvisi nel formato warning: sun.awt.AppContext is Sun proprietary API and may be removed in a future release Non è molto bello, ma per ora lo vivrò.
  • Nel metodo run, ho eseguito il test OK con il metodo simulatePush di oracle.ewt.lwAWT.AbstractButton.
  • Il metodo emulato qui è invokeLater. Per invokeAndWait, è necessario più codice per la chiamata postEvent. Vedi alcune fonti per la classe EventQueue, come punto di partenza.
0

si dovrebbe essere in grado di estendere VButton classe la definizione della classe dovrebbe essere s omething come:

public class AmazingButton extends VButton implements FocusListener 

Allora avete bisogno di un init classe come:

public void init(IHandler handler) 
    { 
    m_handler = handler; 
    super.init(handler); 
    addMouseListener(new ButtonMouseAdapter()); 
    addFocusListener(this); 
    } 

E poi dopo è necessario implementare gli ascoltatori e fare alcune cose in esso:

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 ; 
    } 

    } 

spero questo codice funziona per te.

saluti

+0

Non capisco perché questa dovrebbe essere una risposta alla mia domanda, mi dispiace. Per favore leggi attentamente la domanda. Il mio problema riguarda il richiamo di un metodo GUI nel thread EDT corretto. – manuell

0

ho iniettato con successo il mio codice Java in un Oracle in esecuzione moduli di domanda, utilizzando DLL Injection e alcuni trucchi JNI.

Quello è il vero problema qui, IMO.

si è affetti da bersaglio fissazione, il che significa che, il programmatore, ha un'idea fissa mentale di ciò che tipo di soluzione che vogliono e questo ti impedisce di vedere tutto il resto. La fissazione del bersaglio ha provocato incidenti aerei, in quanto anche piloti con molta esperienza e intelligenza (di fatto intere cabine!) Sono diventati così fissi su un tema in una mentalità da far passare altri disastri.

Esci da questo stato d'animo.

La soluzione desiderata non sta funzionando, quindi andare avanti e provare qualcos'altro. Ti piace l'opzione ragionevole già presentata da @ nightfox79 e le relative varianti.

Si sta tentando di aggirare una classe di oggetti complessa, quando probabilmente si dovrebbe semplicemente estendere la classe esistente che si sta tentando di modificare. Questa è l'intera base dello sviluppo delle OOP.

DLL/JNI Trickery non ha posto in una soluzione ragionevole, IMO.

E ho pietà della persona che deve mantenere e riparare qualsiasi soluzione di codice basata su un hack DLL/JNI. In questo modo giace la pazzia.

La tua teoria che invokeLater() non è in esecuzione con il diritto EDT è probabilmente sbagliato. invokeLater(), in base alla documentazione, , sempre, accoda il codice richiesto sull'elenco di codici in sospeso per il gestore eventi AWT, che è esattamente dove dovrebbe essere. Cercare di aggirare questo è quasi certamente causa di problemi orribili. L'intero scopo di invokeLater() è di posticipare l'elaborazione dei pesi massimi nell'EDT da cui viene richiamato ed eseguirlo successivamente sullo stesso thread esatto. È un bug in invokeLater() in caso contrario, IMO.

Se, tuttavia, si desidera verificare quale codice di thread è in esecuzione, l'unico test che conosco è quello di utilizzare questo nel codice;

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

Non riesco a modificare l'applicazione Oracle Forms. Quando il mio codice iniettato usa 'involkeLater', il' Runnable' alla fine viene eseguito in un thread chiamato 'AWT-EventQueue-0'. Stessa cosa quando uso 'getSystemEventQueue' e' postEvent' con un 'InvocationEvent'. Vedi l'Elenco discussioni nella domanda. L'EDT che dovrei usare si chiama 'AWT-EventQueue-2', ed è effettivamente quello che viene chiamato quando installo un' AWTEventListener'. La domanda riguarda davvero come selezionare il corretto 'EventQueue' /' EDT'. – manuell

+0

In pratica, stai tentando di bypassare ciò che sembra terribilmente una barriera di sicurezza: il tuo codice lancia una SecurityException, dopo tutto. Se non sei autorizzato o in grado di installare il listener di eventi sul thread corretto, probabilmente non dovresti farlo affatto. Probabilmente dovresti accettarlo e trovare una soluzione diversa a qualsiasi cosa tu stia cercando di fornire in termini di funzionalità. A volte questa è l'unica soluzione. – StephenG

+0

Sono autorizzato e in grado di installare il mio 'AWTEventListener', e ricevo correttamente tutti gli eventi, nel thread Java' AWT-EventQueue-2'. La richiesta di "simulare azione del pulsante" viene, in modo asincrono da un altro processo, ed è per questo che ho bisogno di un modo per recuperare il buon EventQueue (perché se uso semplicemente 'getSystemEventQueue' il mio' Runnable' verrà eseguito nel 'AWT-EventQueue- 0 '). – manuell

0

Sto anche cercando di spingere il mio codice Java in una corsa di Oracle Forms, fondamentalmente sto cercando di automatizzare i moduli Oracle flusso tramite l'interfaccia utente, dall'alto commento sembra che hai fatto ottimo lavoro per farlo, si può guidami per questo, ho creato l'agente java, il problema è come iniettarlo nell'applet di moduli Oracle che gira nel web.e il secondo problema è mentre si lavora sul metodo premain nel mio agente java, cosa dovrei usare per l'oggetto form Oracle identificazione, per l'applet normale sto usando Toolkit tk = Toolkit.getDefaultToolkit(); e poi sto ascoltando evento inviato da Windows gentile ha mi guida su questo, sto seriamente affrontando difficoltà per automatizzare questo

1

Per ottenere il corretto filo EDT indipendentemente dal vostro gruppo di thread, è possibile utilizzare SunToolkit.targetToAppContext(Object target), e per il parametro che si può dargli da mangiare la componente AWT su cui intendi agire. Esempio source.

quindi ottenere l'EventQueue utilizzando EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);

Infine, creare un nuovo InvocationEvent con il vostro eseguibile e chiamare post-evento sulla EQ.