Autor Thema: JFrame vs. JDialog und lotus.domino.JavaConnectLoader.findClass  (Gelesen 3553 mal)

Offline C-Box

  • Frischling
  • *
  • Beiträge: 3
  • Geschlecht: Männlich
Hi alle zusammen,

ich habe die Ehre einen Java-Agenten weiterzuentwickeln, den ein ehemaliger Kollege (Gruß an Magi_Halli) damals entwickelt hat.

Vorweg:
Meine Notes-Kenntnisse sind eher "beschränkt" und beruhen auf Google&Co. + Learning by Doing.
Wir benutzen die 8.5er Version.


Es ist ein reiner Java-Agent, der als JAR Archiv komplett per "Projekt bearbeiten" deployed wird.
Er extended NICHT die AgentBase oder irgendwelche anderen Notes Klassen. Reines simples Java-Proggi also. (wird per LotusScript & LS2J aus dem Notes aufgerufen)

Soweit funktioniert im Grunde auch alles wunderbar - wenn auch relative träge.

Nur bin ich gestern auf den Trichter gekommen die GUI des Agenten zu überarbeiten, welche initial nur aus JDialogs bestand. Da diese aber seltsamerweise nicht immer in den Vordergrund kommen, wollt ich aus der Haupt-Gui-Klasse einen JFrame machen, der wenigstens als Fenster in der Windows Taskbar erscheint und somit anklickbar ist.

Gesagt getan, alles refactored und klappt im Eclipse alles wunderbar.

Im Notes jedoch kommt beim Aufruf zwar noch mein JFrame nach oben, wenn ich jedoch auf einen Button klicke, um einen JDialog (Suchdialog) anzuzeigen, erscheint dieser nicht mehr!

In der DebugConsole konnt ich rauskriegen, dass er die benötigten Klassen nicht finden konnte und deshalb dann NullPointers geschmissen hat. Nach einigen Recherchen und Ergebnissen meines Ex-Kolleges habe ich rausgefunden, dass ich mit einer zuvor erstellten Instanz der jeweils angemeckerten Klasse den Fehler umgehen kann...

....okay, so viel sinds im Grunde nicht... einfach mal vorher von allen eigenen & für die Aktion benötigten Klassen eine sinnlose Instanz erstellt. Tja und dann geht's halt irgendwann in die java.awt Klassen runter --- und da hört der Spaß auf. >:(

Hier die Exception:

Code
2009-12-09 10:48:37.019 [de.ibees.notes.addin.gui.AddInMainFrame] ClassLoader of de.ibees.notes.addin.gui.AddInMainFrame is: lotus.domino.JavaConnectLoader
2009-12-09 10:48:44.238 [de.ibees.notes.addin.MailHandler] java.lang.NullPointerException
	at lotus.domino.JavaConnectLoader.findClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:643)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:609)
	at lotus.domino.JavaConnectLoader.loadClass(Unknown Source)
	at de.ibees.notes.addin.gui.SuchDialog.initialize(SuchDialog.java:114)
	at de.ibees.notes.addin.gui.SuchDialog.<init>(SuchDialog.java:101)
	at de.ibees.notes.addin.search.SuchHandler.<init>(SuchHandler.java:95)
	at de.ibees.notes.addin.MailHandler.buttonAPartner_actionPerformed(MailHandler.java:372)
	at de.ibees.notes.addin.MailHandler.actionPerformed(MailHandler.java:289)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2008)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2331)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:400)
	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:255)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:249)
	at java.awt.Component.processMouseEvent(Component.java:6054)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3278)
	at java.awt.Component.processEvent(Component.java:5819)
	at java.awt.Container.processEvent(Container.java:2071)
	at java.awt.Component.dispatchEventImpl(Component.java:4426)
	at java.awt.Container.dispatchEventImpl(Container.java:2129)
	at java.awt.Component.dispatchEvent(Component.java:4256)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4335)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3999)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3929)
	at java.awt.Container.dispatchEventImpl(Container.java:2115)
	at java.awt.Window.dispatchEventImpl(Window.java:2453)
	at java.awt.Component.dispatchEvent(Component.java:4256)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:612)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:286)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:196)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:186)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:181)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:173)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:134)

die besagte Zeile 114 ( this.addWindowListener(new java.awt.event.WindowAdapter() {) des SuchDialoges macht im Grunde nur die simplen Initialisierungen für den Dialog:


Auszug Suchdialog:
Code
this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    this.setLocation(new Point(180, 180));
    this.setResizable(true);
    this.setModal(true); // this wartet auf Ein-/Ausgabe, bevor close
    this.addWindowListener(new java.awt.event.WindowAdapter() {
      public void windowClosing(java.awt.event.WindowEvent e) {
        getButtonAbbrechen().doClick();
      }
    });


Auszug MailHandler (wo der ganze Spaß starten)
Code
public void buttonAPartner_actionPerformed(ActionEvent e) {
    try {
      // Aufruf (+ Auswahl zurückgeben):
      sucheHandler = new SuchHandler(APARTNER_ID);
      Apartner ap = ((Apartner) sucheHandler.getSelectedAPartner());
      if (sucheHandler.isConfirmStatus() == true && ap != null) {
        // comboApartner neu füllen
        comboApartner_fillBySearch();
      }
      else {
        // Nothing
        NotesAddInLogger.info(this.getClass(), "Abbruch in AP-Suche!");
      }
    }
    catch (Exception err) {
      NotesAddInLogger.error(this.getClass(), err);
    }
  }

Der Witz ist, wenn ich die Hauptklasse "AddInMainFrame" wieder von extends JFrame auf extends JDialog umwandle geht der ganze Spaß wieder wunderbar.... es liegt also DEFINITIV am JFrame.

So und nun bin ich mal gespannt, ob mir da einer was erklären kann!??!?!

Irgendwie scheint er die Klassen nicht zu finden, wenn ich vom JFrame aus den Dialog anzeigen will!?!? Nur warum klappt das, wenn die Ursprungsklasse nen Dialog ist?
Ein deployen ins jvm/lib/ext Verzeichnis fällt flach, da ich dann sicherlich Probleme kriege mit dem Deployen auf den Clients, was er so über "Gestaltung aktualisieren" wunderbar schafft.

Hoffe jemand hat nen Tipp
Grüße aus Dresden
Christian

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Hm 2 Sachen zu dem Thema!

Laut meiner Erfahrung wird von der IBM das Thema Swing UIs in Java Agenten oder von JS2J aus nur noch mehr als habherzig unterstützt. Hier passiert schon lange keine Weiterentwicklung und auch keine Fehlersuche mehr. Ich habe mal bei der DNUG in Karlsruhe mit div. IBM Entwicklern über das Thema gesprochen und die haben damals schon darauf verwiesen, dass diese Techniken Java UIs mit Notes zu koppeln durch die Eclipse Integration mit Notes 8 obsolet werden. Also würde ich deine Datenbank auf eine Composite App umbauen mit einer auf SWT und Jface aubauenden Gui versehen wenn möglich.

Zu deiner eigentlichen Frage, habe ich die Vermutung, dass es daran liegt, dass dein JFrame nicht modal ist im Gegensatz zum JDialog. Das heisst, wenn du JFrame subclassed und nicht JDialog, dann bleibt dein hauptthread nicht stehen sondern läuft weiter und springt dann auch in den Lotusscriptcode zurück. Damit wird jedoch der Classloader von LS2J beeinträchtigt. Deshalb kannst du nur Klassen verwenden, die schon einmal instanziert waren. In Eclipse funktioniert das ganze, da du da nicht LS2J Classloader verwendest sondern den nativen Java Classloader. Zum testen baust du einfach nach dem Öffnen deines Jframes eine Endlosschleife ein. Ich bin zuversichtlich, dass dann dein Jframe funktionieren wird. Du musst dann natürlich noch irgendwie eine Abbruchbedingung einbauen, wenn dein Jframe fertig ist. Aber zum Testen müsste die Endlosschleife reichen.

Grüße

Ralf


« Letzte Änderung: 10.12.09 - 09:49:53 von Ralf_M_Petter »
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline C-Box

  • Frischling
  • *
  • Beiträge: 3
  • Geschlecht: Männlich
Hallo Ralf,

danke für die ausführliche Antwort.
Du hattest recht, die Endlosschleife verhindert erstmal das Rückspringen und meine Dialoge kommen wieder hoch.... aber dafür ist nun die CPU bei 100%...

Hier mal der Code:
Code
 mainframe.setVisible(true);
    while(mainframe.isVisible()){
    	// Dummy Schleife
    }
    NotesAddInLogger.debug(this.getClass(), "Nach der EndlosSchleife!");

Anhand der Log seh ich, dass er wirklich erst beim Beenden des Frames diese Schleife verlässt. Aber dafür hängt halt der Rechner mit Volllast.
Wenn ich nun einen Extra Thread mache, der nur "kreiselt" solange der Frame sichtbar ist, kommt es sicherlich auf's gleiche raus wie vorher oder? (der AWT Thread ist beendet und gibt die Steuerung an das LS2J zurück, oder?)

Meine Idee nun, ich generiere einen JDialog, welcher unsichtbar irgendwo im Hintergrund ist und aus dessen Konstruktor erzeug ich meinen Frame (wenn das denn geht, noch nie gemacht). Beim Schliessen des Frames, schliess ich auch meinen BackgroundDialog und vielleicht klappt's dann.

Würde denn ein eigener Classloader weiterhelfen?

Grüße aus DD
Christian

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Ja Ja die Endlosschleife, war ja nur um meinen Verdacht zu bestätigen.

Wir gut bist du denn in Java?

Falls dir Multithreading Programmierung geläufig ist, dann kannst du relativ einfach deinen HauptThread warten lassen, auf irgendein Ereignis in deinem UI ohne die CPU zu belasten. Falls nicht würde ich eher auf der Notesseite ansetzen und schauen, dass deine LSJ Objekte irgendwie am Leben erhalten werden bis dein UI Programm fertig ist. Vielleicht kannst du mal den gesamten Ablauf zusammenfassen, dann könnte man sicher einfacher die ideale Lösung für das Problem finden.

Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline C-Box

  • Frischling
  • *
  • Beiträge: 3
  • Geschlecht: Männlich
Hallo Ralf,

hab es mal mit einem DummyThread probiert... funktioniert einwandfrei - auch in Betracht auf die CPU Last.  Hier mal die Klasse:

Code
package de.ibees.notes.addin.tools;

import de.ibees.notes.addin.gui.AddInMainFrame;

public class LS2JDummyWaitThread extends Thread {
	private static AddInMainFrame frameInstance = null; 
	
	public LS2JDummyWaitThread(AddInMainFrame frame){
		if (frame == null){
			throw new IllegalArgumentException("Frame darf nicht <null> sein!");
		}
		NotesAddInLogger.debug(this.getClass(), "Neuen WarteThread erzeugt!");
		frameInstance = frame;
	}
	
	public void run(){
		while (frameInstance.isVisible()) {			
			if (!this.isInterrupted()){
				try {
					// NÜSCHT Machen, nur kreiseln.... !
					NotesAddInLogger.debug(this.getClass(), "Muss warten...");
					this.sleep(10000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					NotesAddInLogger.debug(this.getClass(), "WarteThread abgebrochen...");
					break;
				}
			}else{
				NotesAddInLogger.debug(this.getClass(), "WarteThread interrupted...");
				break;
			}
		}
	}

}


diesen Thread starte ich nach dem setVisible(true) des MainFrames

Code
    mainframe.setVisible(true);
    dummyThread = new LS2JDummyWaitThread(mainframe);
    dummyThread.start();
    dummyThread.join();
    NotesAddInLogger.debug(this.getClass(), "Ende in MailHandler.initialize() Methode!");

Bei Ok oder Abbrechen wird der dummyThred einfach interrupted.

Vom Prinzip her.
Im Notes soll der User eine Mail in einem Ordner markieren. Über einen Button in der Toolbar wird diese Mail per LotusScript auseinandergenommen (Absender/Body/Attachments etc).... danach wird der Java-Agent gestartet (wie schon initial erwähnt, (noch) keiner der irgendwelche Notes-Klassen erweitert). Der Agent kontaktiert unseren ERP-Server welcher je nach Daten die Kontaktdaten zu dem Absender liefert. Noch paar Userinteraktionen abfragt (Projektbezug, Bezüge, TicketNr generiert und und und... -> teilweise auswählbar aus ComboBoxes etc. oder aber auch suchbar über Suchdialoge (und da klemmte es ja nach Umbau auf JFrame)).
Wird im Agenten nun auf OK geklickert, so wird die Mail quasi ins ERP übertragen und erhält im Notes eine Eingangsnummer (separates Feld).
Das war's auch schon.
Ich will das Ding irgendwann mal als reinen Notes-Agenten implementieren, so dass ich die LotusScript Krücke vorher weglassen kann, aber das wird wohl etwas aufwendig, da ich dies nicht selbst implementiert hab (Gruß an Magic_Halli) und ich so erstmal den LotusScriptCode verstehen muss. :-)

In dem Sinne
Danke für die Zuarbeit, wenn Du noch Verbesserungsvorschläge hast, bin ich natürlich ganz Ohr
Christian

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Prinzipiell funktioniert es natürlich so, aber wesentlich eleganter wäre es mit den neuen Möglichkeiten die Notes 8.x bietet. Dazu solltest du aber erstmal von Swing auf SWT/Jface umsteigen und dann kann man die Funktionalität als Eclipse plugin realisieren.

Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz