# eigene Application und PlugIns



## dzim (12. Nov 2008)

Hallo,

ich hab da mal folgendes Problem:
Ich hab ne Applikation, die einen View mit einem TaskModel (Doppelklick auf Task öffnet irgendwas (Editor/Dialog/Wizard)) hat.
Aus mangelnder Erfahrung oder wie man das auch immer nennen will, lade ich mein Applikationsmodel im Activator der App, da mir das am passendsten schien.
Nun will ich ein PlugIn basteln, das das Model verwendet und sich dort mit einträgt.
So weit so schlecht: Ich hab die Packages für das Modell in der App exportiert, damit das PlugIn sie auch verwenden kann, aber wie bekomme ich die da rein?
Oder wie kann ich der App klar machen, dass sie von allen PlugIns, die das Modell verwenden, dieses und deren Editoren (...) einbindet - oder wie mache ich den PlugIns klar, das sie es bei der App eintragen?
Das PlugIn-Konzept ist mir schon klar, aber an deren Umsetzung happerts gerade ganz entscheidend bei mir... Leider...

Danke!
D


----------



## Wildcard (12. Nov 2008)

ich... verstehe... kein .... wort...


----------



## dzim (12. Nov 2008)

Ich hab's befürchtet.

Ich versuche es mal zu entwirren:

Ich habe eine Applikation mit einem eigenen (Grund-)Modell. Das ist kurz gesagt einfach eine Baumstruktur, die ich entsprechend darstelle.

Ich möchte nun ein PlugIn bauen, das beim Start sein eigenes Modell (welches vom Modell der Applikation abgeleitet ist - die entsprechenden Klassen wurden in dem Manifest exportiert) in meine Applikation lädt.
Oder die App soll das Modell aus dem PlugIn laden - je nachdem, wie es überhaupt funktioniert.

Kann ich denn ein PlugIn vielleicht manuell starten?

Leider weiß ich gerade nicht, wie ich es besser erklären könnte und leider gibt es in meiner Firma niemanden, der mit Eclipse RCP arbeitet - ich kann also niemand mit meinen Fragen quälen ausser euch....
Sorry!


----------



## Wildcard (12. Nov 2008)

So wie sich das anhört sollte dein basis plugin sein Modell nicht hart verdrahten, sondern entweder Extension Points anbieten, oder mit OSGi Services arbeiten. Schau dir vielleicht auch mal EMF an. Da kannst du Modelle erweitern und die Packages registrieren. Ohne mehr über den Hintergrund zu wissen kann ich aber nicht beurteilen ob es zum Problem passt.


----------



## dzim (12. Nov 2008)

Ok.
Ich denke mal fast, das bringt hier alles nichts...

Vielleicht geht es ja anders: Kann man ein PlugIn aus einer laufenden Anwendung heraus manuell starten?
Also dass ich meinetwegen in irgendeiner registry schaue, welche PlugIns existieren und ich dann dieses manuell lade.
Idealerweise vielleicht nach PlugIn-ID-Muster oder so...


----------



## dzim (12. Nov 2008)

> So wie sich das anhört sollte dein basis plugin sein Modell nicht hart verdrahten, sondern entweder Extension Points anbieten, oder mit OSGi Services arbeiten. Schau dir vielleicht auch mal EMF an. Da kannst du Modelle erweitern und die Packages registrieren. Ohne mehr über den Hintergrund zu wissen kann ich aber nicht beurteilen ob es zum Problem passt.



Ja - du hast recht: Es gibt ein bereits erstelltes BasisModel, dass andere Plugins erweitern sollen.
Ich versuche mich mal in den von dir gennanten Punkten - erst mal Extension Points, dann OSGi Services - aber für EMF wird mir schlich die Zeit fehlen.
Notfalls muss ich es erst mal fest in die Anwendung einarbeiten, so dass ich, wenn ich mal wieder mehr Zeit dafür habe, es dann umarbeiten kann....

Vielen Dank jedenfalls!


----------



## dzim (12. Nov 2008)

Also ich habe die Extension Point-Variante mal probiert - obwohl das neu für mich ist, hat das Tutorial von Lars Vogel weitergeholfen.
Ich habe ein Model (in meinem Haupt-PlugIn) das es von anderen PlugIns zu extenden gilt.
Habe ich alles fein in dem EP angegeben und so geladen wie LV in seinem Tutorial, nun bekomme ich aber eine Exeption in meiner Anwendung, die ich mir mal hab auf die Konsole schreiben lassen.
In der Fehlermeldung steht vielles, aber wirklich schlau werd ich daraus nicht...


```
org.eclipse.core.runtime.CoreException: Plug-in com.ipoque.p2p.tracker.rcp.exporter was unable to load class com.ipoque.p2p.tracker.rcp.exporter.model.ExporterTaskModel.
	at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.throwException(RegistryStrategyOSGI.java:180)
	at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:162)
	at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:867)
	at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
	at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:51)
	at com.ipoque.p2p.tracker.rcp.pfs.PFSActivator.runTaskModelExtension(PFSActivator.java:108)
	at com.ipoque.p2p.tracker.rcp.pfs.PFSActivator.<init>(PFSActivator.java:45)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at java.lang.Class.newInstance0(Class.java:355)
	at java.lang.Class.newInstance(Class.java:308)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:141)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:980)
	at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:265)
	at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:400)
	at org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:111)
	at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:427)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:193)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findLocalClass(BundleLoader.java:368)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:444)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:397)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:385)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:87)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.loadClass(BundleLoader.java:313)
	at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:227)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadClass(AbstractBundle.java:1274)
	at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:160)
	at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:867)
	at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
	at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:51)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:188)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:386)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:549)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:504)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1236)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1212)
Caused by: org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter$TerminatingClassNotFoundException: An error occurred while automatically activating bundle com.ipoque.p2p.tracker.rcp.exporter (49).
	at org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:125)
	at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:427)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:193)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findLocalClass(BundleLoader.java:368)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:444)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:397)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:385)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:87)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
	at org.eclipse.osgi.framework.internal.core.BundleLoader.loadClass(BundleLoader.java:313)
	at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:227)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadClass(AbstractBundle.java:1274)
	at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:160)
	... 45 more
Caused by: org.osgi.framework.BundleException: The activator com.ipoque.p2p.tracker.rcp.exporter.PFSManagerExporterPlugInActivator for bundle com.ipoque.p2p.tracker.rcp.exporter is invalid
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:146)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:980)
	at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:265)
	at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:400)
	at org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:111)
	... 57 more
Caused by: java.lang.NullPointerException
	at com.ipoque.p2p.tracker.rcp.exporter.PFSManagerExporterPlugInActivator.<init>(PFSManagerExporterPlugInActivator.java:37)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at java.lang.Class.newInstance0(Class.java:355)
	at java.lang.Class.newInstance(Class.java:308)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:141)
	... 62 more
```


----------



## Wildcard (12. Nov 2008)

Das hier ist der echte Fehler:
Caused by: java.lang.NullPointerException
   at com.ipoque.p2p.tracker.rcp.exporter.PFSManagerExporterPlugInActivator.<init>(PFSManagerExporterPlugInActivator.java:37)


----------



## dzim (13. Nov 2008)

Danke!
Das hat den Fehler behoben und das Modell wurde erfolgreich geladen.

Nun steh ich aber vor dem nächsten Problem:
Das untergeordnete PlugIn hat (oder besser: soll haben) eine Reihe von Editoren und alles was dazu gehört (Input, spezielle Dialoge, u.s.w.) die gestartet werden sollen, wenn man nun auf einen entsprechenden Eintrag des Modells klickt.
Das klappt auch für die von meiner Applikation (Haupt-PlugIn) mitgelieferten Editoren u.s.w., aber nicht für die aus dem PlugIn.
Schuld ist, so ich es richtig verstehe, sicher das Classloader-pro-PlugIn-Konzept. So kann der Klassloader des Hauptplugins logischerweise nicht auf die Klassenstruktur des untergeordneten PlugIns zugreifen - die Frage ist: läßt sich das beheben/umgehen?
Das Haupt-PlugIn soll ja die Editoren u.s.w. nutzen, die das untergeordnete PlugIn Anbieten... sonst wär das ganze ja sinnfrei...


----------



## Wildcard (13. Nov 2008)

Hört sich fast so an als wolltest du eine zirkuläre Abhängigkeit aufbauen. Das ist eine ganz schlechte Idee.
Überhaupt bin ich mir nicht so sicher das du den richtigen Weg gehst. Setz dich doch mal in Ruhe hin und überleg was du haben möchtest, wie das andere Eclipse PlugIns tun und wie es sich auf deinen Anwendungsfall anwenden lässt.
Deine Beschreibungen sind leider sehr vage, aber so wie es sich anhört, könnte durchaus sein, dass das Common Navigator Framework deine Probleme eleganter lösen könnte.


----------



## dzim (13. Nov 2008)

Hm.

So hab ich das noch nicht gesehen.

Ich versuch es mal in Worte zu fassen, was ich mir technisch gesehen vorstelle.

Besagtes Haupt-PlugIn (=Applikation) bietet eine Reihe von Interfaces, Abstrakten Klassen u.ä. an. (unter anderem das ganz oben genanntes Task-Modell)
Es soll selbst in der Lage sein, eine Reihe von eigenen Editoren, Dialogen, Wizards, die über die Tasks identifiziert werden, zu öffnen (das klappt bereits Musterhaft für einen Editor - mit vollem Funktionsuzmfang)

Ich habe aber auch noch eine Reihe von Aufgaben, die zwar grob was mit dem Hauptprogrsamm zu tun haben, aber eben nur grob.
So dachte ich mir, ich baue PlugIns, die das Task-Modell, also die zu öffnenden Editoren, Dialog u.s.w, des Hauptprogramms erweitern (b.z.w. derzeit, dass das Hauptprogramm nach PlugIns mit dem entsprechenden Extension Point schaut und es von dort lädt.) UND auch noch deren Implementierung mitbringen - damit das Hauptrogramm sauber bleibt.

Ich hielt die Rangehensweise eigentlich für recht klar struckturiert und sauber, aber.... nun ja - in Unwissenheit kann man vieles total klar struckturiert und sauber finden...


----------



## Wildcard (13. Nov 2008)

Um einen Editor zu öffnen musst du nicht zwangsläufig den Editor kennen. Einfach IDE.openEditor.
Mal angenommen dein Modell wird in einem Baum angezeigt. Hier könnte das CNF ins Spiel kommen.
Andere PlugIns stellen zusätzliche ContentProvider, LabelProvider und Actions bereit. Das könnte dann auch eine Open Action sein, die bei Doppelklick einen Editor XY öffnet.
Wichtig ist, dass dein Basis PlugIn keinesfalls die Kinder kennen darf, also musst du dafür eine Lösung finden.


----------



## dzim (13. Nov 2008)

IDE.openEditor() würde aber eben nur u.U. mit dem Editor klappen, nicht mit dem in dem entsprechenden PlugIn angelegten EditorInput - an den komm ich ja ob des "falschen" Classloaders nicht heran.
So gesehen macht es Sinn, CNF zu nehmen. Aber: So muss jedes PlugIn ja wieder seinen eigenen *Provider mitbringen - ok, den könnt ich ja per (durchaus gewünschter) Abhängigkeit aus dem Haupt-PlugIn laden. Das selbe gilt für die Öffnen Action.
Ich weiß zwar nicht genau was du mit


> Wichtig ist, dass dein Basis PlugIn keinesfalls die Kinder kennen darf, also musst du dafür eine Lösung finden.


meinst, aber mein größtes Problem ist, das ich mit dem CNF noch nich wirklich warm geworden bin - bislang hat es mir nie was angezeigt.

Wie müsste theoretisch der Aufbau der PlugIns dann sein? Müssten alle PlugIns CNF in der Extension haben? Ich geb zu, da ist mir das Framework noch höchst schleierhaft...

Ach so: Was hälst du (ihr  ) von dem hier?
www.martinlippert.com/publications/JS-Classloading-in-Eclipse-final-web.pdf
(Speziell Seite 6 und 7)


----------



## Wildcard (13. Nov 2008)

Denk doch mal drüber nach: Wenn deine erweiterten PlugIns abhängig von dem Basis Plugin sind und dein Basis Plugin die erweiterten PlugIns kennt, wer muss dann zuerst kompiliert werden?



> IDE.openEditor() würde aber eben nur u.U. mit dem Editor klappen, nicht mit dem in dem entsprechenden PlugIn angelegten EditorInput - an den komm ich ja ob des "falschen"


Dazu fallen mir verschiedene Wege ein. Es gibt beispielsweise ein URI basiertes öffnen von Editoren. Ebenso könntest du über das Adapter Framework gehen:

```
deinModel.getAdapter(IEditorInput.class)
```



> Wie müsste theoretisch der Aufbau der PlugIns dann sein? Müssten alle PlugIns CNF in der Extension haben?


Naja, deine PlugIns erweitern die View über die CNF Extension Points.


----------



## dzim (13. Nov 2008)

> Denk doch mal drüber nach: Wenn deine erweiterten PlugIns abhängig von dem Basis Plugin sind und dein Basis Plugin die erweiterten PlugIns kennt, wer muss dann zuerst kompiliert werden?


*amKopfKratz* klingt schon komisch, stimmt schon, aber so wollte ich es auch nicht haben (nur wär's vermutlich geworden).

Also Ich werd mir - wenn ich mal dafür Zeit hab *hustHust* (wann das wohl mal wird) - das ganze mal anschaun - oder jemanden "überzeugen" es für mich zu tun und es mir dann zu erklären... Je nachdem was zuerst eintritt...

Danke jedenfalls! Du hast mich (auch gedanklich und was meine nächsten Ziele angeht) ein ganzes Stück weiter gebracht!

PS: mir ast da noch ein unsauberer Workaround eingefallen - du wirst ihn hassen:
Man könnte - wenn man denn wollte - in meinem Modell, das als Klasse ja bereits über den Extension Point übergeben wird, "einfach" den lokalen Classloader eintragen - absolut unsauber, könnte aber rein theoretisch funktionieren, da der Classloader ja die Klassen in seinem Kontext kennt...
Aber ist wirklich nen dirty hack!


----------



## Wildcard (13. Nov 2008)

dzim hat gesagt.:
			
		

> Man könnte - wenn man denn wollte - in meinem Modell, das als Klasse ja bereits über den Extension Point übergeben wird, "einfach" den lokalen Classloader eintragen - absolut unsauber, könnte aber rein theoretisch funktionieren, da der Classloader ja die Klassen in seinem Kontext kennt...
> Aber ist wirklich nen dirty hack!


Das zeigt mal wieder, egal wie sehr man sich bei der OSGi Spezifikation bemüht hat die Stellen zu eliminieren an denen sich Entwickler selbst in den Fuß schießen können, ein hartnäckiger Entwickler findet *immer* einen Weg sich selbst in den Fuß zu schießen.


----------



## dzim (13. Nov 2008)

*lol*

Stimmt.

Ich denke, auch wenn ich das Problem noch nicht wirklich behoben hab, bin ich auf einem Guten Weg dahin - CNF ruft - dann kann ich den Thread ja erst mal schließen.
Ist eh nicht das letzte mal, das man von mir hört...


----------

