Strukturierung und Dependencies in RCP mit SWT und JFace

(Edit: Ester Beitrag kopiert und Rest verschoben von http://forum.byte-welt.net/java-forum/awt-swing-javafx-swt/18062-jface-checkboxtreeviewer-aktualisieren-unglaublich-langsam.html#post127270 )

Hmja, es war schon etwas irritierend, dass bei einer Suche nach “jface download” praktisch keine Ergebnisse kommen (zumindest keine, die über “Such’ dir den Sche!ß halt selbst zusammen” hinausgehen :rolleyes: ). Zum Glück gibt es ja sowohl für SWT als auch JFace viele “Snippets”, wo man schonmal was zum Ausprobieren hat. Aber die Erklärungen kommen da (im Vergleich zu den ausführlichen “How to use…”-Seiten für die Swing Components) schon etwas zu kurz.

Insgesamt mache ich gerade die ersten Experimente mit SWT und JFace. Die Anforderungen sind (Projektseitig) noch nicht ganz klar (und wahrscheinlich werden sie wieder mal nach der Deadline geklärt, durch Beschwerden “Dies-und-das hätte aber so-und-so sein sollen!” :rolleyes: ). Aber der Baum wird wohl schon notwendig sein. Dieses “1 root, 10000 blätter” war für den Test. Im Extremfall könnte er zwar recht flach mit “mehreren hunderttausend” Blättern sein, aber der relevante(ste) Fall wäre wohl was mit ~5-10 Ebenen und ~10000 Blättern.

Mit den SWT.VIRTUAL und LazyContentProvider hatte ich auch rumprobiert (nachdem es eben erst so langsam war, waren das die Richtungen, in die die ersten Suchergebnisse gingen). Aber das schien dann schon deutlich komplizierter… gerade der LazyContentProvider wäre dann was, wo man sich etwas mehr Zeit zum Reinfräsen nehmen müßte, und soweit ich das sehe, wäre es da notwendig, dass die Knoten ihre parents kennen müßten - was nur ganz schlecht mit dem Datenmodell vereinbar wäre.

Welche Alternativen für die updates es da gibt, … ja, ich hatte ein bißchen rumgesucht und rumprobiert, und auch mal im Profiler geschaut, wo da die Zeit flöten geht, aber … die verschwindet eben irgendwo den den Tiefen von (geschätzt) >100-Zeiligen Aufrufbäumen, wo die Beantwortung der Fragen

  1. Was macht der da?
  2. Warum macht er das?
  3. Warum dauert das so lange?
    nicht in vertretbarer Zeit möglich wäre. Und der Anwendungsfall (ein Baum mit 1000 Knoten) und die Aufgabe (Beschriftung der Knoten ändern) erschienen mir SO alltäglich, und die benötigte Zeit (ich meine, 5 Sekunden!? Haaaalllooo?) erschienen mir SO lächerlich-absurd hoch, dass ich davon ausgehen mußte, da etwas grundsätzlich falsch zu machen.

(Inzwischen finde ich, dass nicht ICH etwas falsch gemacht habe, sondern der, der meinte, “setUseHashlookup(true)” nicht zum default zu machen, aber … man muss sich wohl damit abfinden… )

Dieses “Nebula” sieht schonmal ganz interessant aus. Ich werde da mal ein Auge drauf behalten, auch wenn ich im Moment davon ausgehe, dass ich das nicht verwenden darf. (In der Leistungsbeschreibung steht sinngemäß, dass das Paket keine Abhängigkeiten haben darf. Da steht speziell(!) auch: Keine Abhängigkeiten zu Eclipse. Gut, es soll zwar ein Eclipse-Plugin sein, aber … naja, nichts wird so heiß gegessen, wie es gekocht wird :rolleyes: )

Da wünsch ich dir dann mal viel Spaß :wink: Gerade im Hinblick auf solche Bug-Reports 129457 – Virtual Tree very slow

Hab mal ein gutes Jahr an einem Legacy-RCP-Projekt arbeiten dürfen und kann jeglichen Schmerz nachvollziehen, da dort alles was man nur so falsch machen kann, falsch gemacht wurde. Das schlimmste daran war das das Ding Oberflächlich auch noch das getan hat, was es tun sollte, wenn man von den Ewigkeiten absieht, die das Programm zum Starten gebraucht hat. Aber irgendwann gewöhnt man sich an die 2 Minuten die man nach dem Drücken von run warten darf, bevor man sieht ob die Änderung was gebracht hat.

Das mit den Abhängigkeiten kann ich voll und ganz verstehen. Irgendwann wird dann aus einem Build mit 30 MB einer mit 50, dann mit 60 und irgendwann mit 200 MB, weil jede Abhängigkeit weitere Abhängigkeiten in verschiedenen Versionen voraussetzt.

Das keine Abhängigkeit zu Eclipse bestehen darf klingt etwas absurd ist aber das Beste was man machen kann. Sobald da eine Abhängigkeit Richtung Eclipse dranhängt, dauert es nicht lang und man darf die komplette Runtime zum entwickeln starten. Und das dauert eben. Dann kommt man noch auf die Idee, das ganze im Debug-Mode laufen zu lassen und auf das Hot-Code-Replacement zu setzen um das ständige Neustarten halbwegs zu vermeiden, was aber nur bei Code funktioniert, der nicht während dem Bootstraping geladen wird. Und wenn man dann doch beim starten ist, dann darf man sich auch noch jedes mal mit Username und Password anmelden.

Ohne Abhängigkeit erstellt man sich ein paar Klassen im test-folder mit main-Methode und startet das ganze.

Ja, den werd’ ich wohl sowieso noch haben, aus diesen und vielen anderen Gründen. Den Bug-Report könnte ich mangels Einblick zwar lesen, aber ohnehin nicht nachvollziehen. Bisher hatte ich mit SWT praktisch nichts gemacht, geschweige denn mit JFace. (Ich bin ja bekennender Swinger <3 :D). Bei dem wenigen davor war mein erster Eindruck von SWT nicht so besonders, und das festigt sich jetzt. JFace scheint ein netter Versuch zu sein, aber … als Abstraktionsschicht bei weitem nicht dick genug, und wenn ich mir den Grund für diesen Thread (und anderes, was ich so lese) ansehe, scheint da schon einiges im Argen zu liegen.

Also, manche GUI-Components sind deutlich komplizierter, als sie im ersten Moment aussehen. Tabellen und Bäume, hauptsächlich. Und wenn es in Swing eine Klasse gibt, die ich „sperrig“ finde, dann JTree. Man ist irgendwie immer gezwungen, an allen möglichen Stellen von einem Default... (MutableTreeNode etc) auszugehen. Aber wenn man den tree nicht zu sehr customizen will, ist das dann auch OK. Zum Test habe ich gerade mal innerhalb von wenigen Sekunden ein

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
        DefaultTreeModel model = new DefaultTreeModel(root);
        for (int i=0; i<1000000; i++)
        {
            DefaultMutableTreeNode child = 
                new DefaultMutableTreeNode("child"+i);
            model.insertNodeInto(child, root, i);
        }
        JTree tree = new JTree(model);

hingeschrieben, und der erstellt das innerhalb von 2 Sekunden (und feuert dabei brav 1 Million Events), und der Baum ist einfach da, und man kann ihn ohne die geringste Verzögerung einklappen usw.

(Nebenbei: Die Option, dort schlicht einen JTree zu nehmen, und den mit der SWT_AWT da rein zu klatschen, behalte ich noch im Auge. Das hat zwar auch einiges an Problempotential (Events, Selections, Threading…), aber … eine Option könnte es sein)

Das ist eines der Probleme. RCP ist ziemlich komplex, und bringt viele Konzepte mit, die man GUT kennen muss, um da vernünftige Anwendungen zu bauen. Zum Glück habe ich genug Zeit, um mich da einzuarbeiten, bevor das Produkt geliefert werden muss.
pft.
Prrrdf.
Muuaaahahaha :o)
aber mal im Ernst: Mehr als „Schnipsel von Vogella zusammenkopieren, und hoffen, dass es irgendwie laufen wird“ kann ich eben nicht machen.

[QUOTE=ionutbaiu;127475]
Das keine Abhängigkeit zu Eclipse bestehen darf klingt etwas absurd ist aber das Beste was man machen kann. Sobald da eine Abhängigkeit Richtung Eclipse dranhängt, dauert es nicht lang und man darf die komplette Runtime zum entwickeln starten.[/QUOTE]

Ja, ich weiß, dass es einerseits absurd klingt, aber es nicht notwendigerweise absurd ist (bzw. genauer ausdifferenziert werden müßte).

Die damit verbundene Frage, etwas allgemeiner (und schwammiger) formuliert ist ja: Wie viel von dem Code ist „spezifisch für Eclipse“. Sinngemäß könnte man ja eine komplette Anwendung in reinem SWT schreiben, und dann nur die 3 Haupt-Composites jeweils mit einer dünnen „Eclipse-Part-Schicht“ umwickeln und das dann „Eclipse Anwendung“ nennen. Je tiefer die Integration geht, umso schwieriger wird die Trennung. Wenn man an einer Stelle den global-galaktischen Workbench-Selection-Service ansprechen/verwenden will, kommen zwangsläufig Eclipse-Spezifika in die Applikation rein.

Meine (persönliche, grobe) Richtung ist aber bisher ohnehin, solche Abhängigkeiten zu minimieren. (Das „absurd“ bezog sich aber nicht zuletzt darauf, dass man ja schon SWT (und vor allem JFace) als Teile von Eclipse ansehen muss…)

Ein wichtiger Punkt, um diese Abhängigkeiten zu reduzieren, ist ja wohl bei Eclipse 4 dazugekommen. Durch diese ganze Dependency Injection Magie kann man bestimmte Komponenten ja relativ gut von Eclipse selbst entkoppeln (einfache, suggestive Beispiele gab es da z.B. auf Eclipse 4 (e4) Tutorial: Part 2 – Application Model and Views « EclipseSource Blog ). Aber diese ganze Infrastruktur ist eben auch etwas, was man eigentlich erst verinnerlichen müßte, bevor man es produktiv einsetzen kann.

Als Beispiel: Ich habe ein „übergeordnes“ Objekt gebraucht - also eins, das ggf. für mehrere Parts benötigt wird. Und was macht man da? Na klar, man erstellt einen OSGI-Bundle-Activator für das Plugin, registriert eine ServiceFactory im Eclipse-Context, und kann sich dann mit einer dependency-injection-Annotation das passende Objekt injecten lassen. Alles klar? Ich hab’ dann einfach new... verwendet. Es muss ja auch irgendwann fertig werden.

Richtig lustig wird das ganze durch eine weitere Anforderung: Das ganze soll erstmal mit Eclipse 3.8 laufen, aber später dann auch mit Eclipse 4 :rolleyes:

Das ist das schöne an RCP-Projekten, man hat immer was zu lachen. :o)

global-galaktischen Workbench-Selection-Service … Aber diese ganze Infrastruktur ist eben auch etwas, was man eigentlich erst verinnerlichen müßte, bevor man es produktiv einsetzen kann.

Jo, und bei 3.x darfst du schauen wie du an das Zeug, von dem du nicht mal weißt das es das gibt, über zig verschiedene Pfade rankommst. Und wenn du das Teil dann hast, dann hast du ne Fette Abhängigkeit drin und das läuft dann nur noch wenn du ein komplettes Eclipse startest.

Mal als direkten Vergleich E4/EAS/Selection - Eclipsepedia

Jo, und dieses OSGI-Bundle-Activator-Schlag-Mich-Tot kann man auch sein lassen und statt dessen ein paar GoF-Singletons verstreuen damit jeder weiß dass man schon mal was von Design-Pattern gehört, aber nichts von Oo verstanden hat. Ich freu mich für dich solange ein new… funktioniert. Wenn du allerdings einmalig einmal das ganze via OSGI gemacht hast, dann ist das in Zukunft ein, Achtung Buzzword: No-Brainer. Copy-Paste, sieht immer gleich aus. Meine Entscheider hatten sich damals für Singleton entschieden und selbst das verbockt.:rolleyes:

Ich packe es besser mal in OT. Edit von Marco13: Thread-Teil abgetrennt, jetzt ist es „on topic“ :wink:

Naja, irgendwie ist das schon alles recht gehirnverknotend. Wenn man „irgendein“ Objekt braucht, das schon in der Eclipse-Welt existiert, steht überall so lapidar: „Joa, schreib’ einfach @Inject hin, dann kommt die Eclipse-Fee und zaubert dir das Objekt da hin“. Das funktioniert zwar auch. Aber wenn man eigene Objekte in diese Welt bringen will, wird’s kompliziert. Jedenfalls hab’ ich hier jetzt mit irgendwelchen ContextProviderServices und ContextFunktions und OSGi-Servicedeklarationen rumgepfuscht, aber es fügt sich einfach nicht „stimmig“ zusammen. Ich vermute aber, dass das damit zusammenhängt, dass die Projektanforderungen nicht ganz klar sind. RCP-seitig scheint das ganze sogar zu funktionieren, auch wenn die Magie, die dahinter steckt, etwas unbehaglich ist: Man schreibt irgendwo eine service.xml, referenziert die von der manifest aus, vergibt irgendwelche Namen und IDs, und registriert irgendwelche Funktionen irgendwo, und rubbeldiekatz spuckt diese Rube-Goldberg-Maschine irgendwo ein Objekt aus, bei dem niemand weiß, wo es herkommt und wo es hingeht (und ob das immer dieselbe Instanz ist, oder immer verschiedene, oder was man machen muss, wenn es das eine ist aber man das andere braucht, weiß irgendwie niemand so genau…)

Kann es sein, dass du mit Dependency-Injection-Frameworks bisher nicht so viel zu tun hattest? :wink:

Zumindest nichts, was über ein Überfliegen der Google-Guice-Einführungs-Wiki-Seite hinausging :wink: begleitet von dem Gedanken: „Ja, das könnte schon manchmal praktisch sein“, und (wichtig:) „…und ich kann mir grob vorstellen, wie das implementiert ist“ (!). Bei RCP kommt eben SO eine gigantisch-komplexe Infrastruktur dazu, dass, selbst wenn es funktioniert (und ich war schon gelegentlich überrascht, dass es so (gut) funktioniert hat), dieses unbehagliche Bauchgefühl bleibt: „Wenn das jetzt nicht funktioniert hätte, wäre schon der Gedanke lächerlich, auch nur in Betracht zu ziehen, zu versuchen, herauszufinden, woran das denn lag“ -_-

Ich sehe die Vorteile, die Modularität, und insbesondere den Gedanken beim E4 Application Model, aber wenn man nicht die Möglichkeit hat, sich das mal gemütlich reinzuziehen (und wenn’s nicht funktioniert, sucht und probiert man rum, bis es geht), sondern konkrete Ergebnisse erwartet werden (nebulös mit den Händen wedelt: aber welche das sind, mussen wir noch sehen…), dann kann das unbehaglich sein.

Zumindest habe ich auch zuhause 1, 2 Anwendungen, für die ich schonmal RCP in Betracht gezogen hatte - jetzt auch noch Kohle dafür zu kriegen, mir das mal anzusehen, ist nicht das schlimmste (bis zur Deadline ist’s noch weeeeit hin, die ist erst nächstes Jahr:wink: )