Modulare Anwendungen und die Lookup API Geertjan Wielenga NetBeans Team Deutschsprachige Überarbeitung, Aljoscha Rittner NetBeans Dream Team Die Notwendigkeit modularer Anwendungen Certified Engineer Course Die Notwendigkeit modularer Anwendungen Certified Engineer Course Die Notwendigkeit modularer Anwendungen Certified Engineer Course Die Notwendigkeit modularer Anwendungen • Anwendungen werden immer komplexer • Sie werden aus Einzelstücken zusammen gesetzt > Frameworks, 3rd Party Bibliotheken, Legacy Bibliotheken • Entwicklung durch verteilte Teams • Komponenten mit umfangreichen Abhängigkeiten • “Gesunde” Architektur erwartet: > Wissen über Abhängigkeiten und > Die Verwaltung der Abhängigkeiten Certified Engineer Course Die Entropie von Software • Version 1.0 ist sauber entwickelt... Certified Engineer Course Die Entropie von Software • Version 1.1... einige zweckmäßige Erweiterungen und Hacks... ...wir werden das in 2.0 schon wieder richten. Certified Engineer Course Die Entropie von Software • Version 2.0...nun ja...aber...es läuft! Certified Engineer Course Die Entropie von Software • Version 3.0... Hilfe! Jeder reparierte Fehler erzeugt zwei weitere! Certified Engineer Course Die Entropie von Software • Version 4.0 ist sauber designed. Eine komplette Neuentwicklung. Zwar ein Jahr zu spät, aber es läuft... Certified Engineer Course Die Entropie von Software • Version 4.1... Das erinnert mich doch an etwas?.... Certified Engineer Course Die Entropie von Software • Fortsetzung folgt.... Certified Engineer Course Modulare Anwendungen • Wissen um ihre Komponenten zur Laufzeit • Dürfen Komponenten während der Laufzeit hinzufügen, entfernen und neu laden • Müssen Abhängigkeiten zwischen Komponenten erkennen • Bieten API Vereinbarungen zwischen Komponenten • Laufen in einem Runtime Container Certified Engineer Course Was macht ein Runtime Container? • Lebenszyklus der Anwendung > Startet und beendet die Anwendung > (De)installiert Module • Modul Verwaltung • Classloading und Modulisolation • Service Registry & Zugriffs API Certified Engineer Course Was ist der NetBeans Runtime Container? Certified Engineer Course Demo 1: NetBeans Runtime Container Certified Engineer Course Der NetBeans Runtime Container • Fünf NetBeans Platform Module Nur diese 5 zusammen: compile & run, mehr wird nicht benötigt. • Ausschließlich diese Module werden von allen NetBeans Platform Anwendungen benötigt. • NetBeans Platform Anwendungen müssen nicht (Rich) Client Applikationen sein • Es sind auch modulare Server Anwendungen denkbar > z.B. mit dem CronJob Plugin zeitgesteuerte Dienste ansteuern Certified Engineer Course Was ist ein NetBeans Module? • Nur ein JAR File – keine Magie > Es besitzt spezielle Manifest-Einträge für das NetBeans Modul-System, die in den Project Properties für Module Projekte bearbeitet werden können. • Verteilt in einem NBM File > Grundsätzlich ein signiertes JAR File > Enthält Metadaten über das Modul > Darf 3rd Party JARs enthalten, oder alles andere Notwendige für das Modul zur Installation Certified Engineer Course Demo 2: Ein NetBeans Modul erstellen Certified Engineer Course Demo 3: Verteilen eines NetBeans Moduls Certified Engineer Course NetBeans Modul Manifest Manifest­Version: 1.0 Ant­Version: Apache Ant 1.7.1 Created­By: 1.5.0_14­b03 (Sun Microsystems Inc.) OpenIDE­Module­Public­Packages: ­ OpenIDE­Module­Module­Dependencies: org.jdesktop.layout/1 > 1.7, org.n etbeans.api.java/1 > 1.18, org.netbeans.api.java.classpath/1 > 1.0 OpenIDE­Module­Java­Dependencies: Java > 1.5 OpenIDE­Module­Build­Version: 200907230101 OpenIDE­Module­Specification­Version: 2.16.2.5.1.1 OpenIDE­Module: org.netbeans.modules.java.editor/1 OpenIDE­Module­Implementation­Version: 5 OpenIDE­Module­Localizing­Bundle: org/netbeans/modules/java/editor/Bundle.properties Certified Engineer Course NetBeans Module Manifest OpenIDE­Module­Layer: org/netbeans/modules/java/editor/resources/layer.xml OpenIDE­Module­Requires: org.openide.modules.ModuleFormat1 OpenIDE­Module­Install: org/netbeans/modules/java/editor/JavaEditorModule.class AutoUpdate­Show­In­Client: false Certified Engineer Course Runtime Container Aufgaben • Sicherstellen, dass Abhängigkeiten aufgelöst sind > Auch mit der Notwendigkeit von vorgegebenen Versionen • Verhindern von ungültigen Abhängigkeiten > Falsche Version, falsches Betriebsystem (→ Token) • Erlauben von gültigen Abhängigkeiten • “Booten” von Komponenten während der Laufzeit Certified Engineer Course Modul Abhängigkeiten erzwingen Certified Engineer Course Demo 4: Abhängigkeits Verwaltung Certified Engineer Course Verwende vorhandene Runtime Container Home-made Framework 1995-2009 Ruhe in Frieden, Home-made Frameworks 1995-2009 Certified Engineer Course Modul Abhängigkeiten Certified Engineer Course Trennung der Implementation von der API • Die API kann in einem Modul deklariert werden, die Implementation in einem anderen Modul • Module verwenden die API nur, wenn die Abhängigkeit dazu deklariert wurde Certified Engineer Course Modulare Bibliotheken Certified Engineer Course Abhängigkeiten ermitteln ? ● Wie findet die SpellChecker API sein Implementation? Certified Engineer Course Abhängigkeiten ermitteln ? ● Wie findet die SpellChecker API sein Implementation? Oder generell, wie ermöglicht es NetBeans den Modulen sich in der Applikation zu finden? Certified Engineer Course Der Java Extension Mechanismus (nahezu) • Im JDK seit 1.3 • Einfach mit JDK 6's ServiceLoader.load() • Deklarative Registrierung • Text Datei(en) in META-INF/services > Name ist Interface > Inhalt ist FQN der Implementation Certified Engineer Course Demo 5: ServiceLoader, die Java-Lösung • Das Interface public interface TextFilter { String process(String s); } • Die Implementation public class UpperCaseFilter implements TextFilter{ public String process(String s) { return s.toUpperCase(); } } Certified Engineer Course Demo 5: ServiceLoader, die Java-Lösung • Registrierung der Implementation > Textdatei in METAINF/services • Load the Interface String s = textArea.getText(); ServiceLoader<TextFilter> filters = ServiceLoader.load(TextFilter.class); for (TextFilter textFilter : filters) { if (filters != null) { s = textFilter.process(s); } } textArea.setText(s); Certified Engineer Course Demo 6: Lookup/Dependency Verwaltung String s = textArea.getText(); Collection<? extends TextFilter> filters = Lookup.getDefault().lookupAll(TextFilter.class); for (TextFilter textFilter : filters) { if (!filters.isEmpty()) { s = textFilter.process(s); } } textArea.setText(s); Certified Engineer Course Die NetBeans Registrierung • Vereinfachte Registrierung durch Annotationen > Keine selbstgeschriebene Plain-Text-Dateien mit Tippfehlern > Registrierungsinformation direkt an der annotierten Klasse > Refactoring funktioniert > Trotzdem Deklarativ, weil zur Compilezeit die Annotationen ausgewertet werden. Certified Engineer Course Die NetBeans Registrierung • Registrierung und Implementation in einer Klasse import org.netbeans.spi.TextFilter; import org.openide.util.lookup.ServiceProvider; @ServiceProvider (service=TextFilter.class) public class UpperCaseFilter implements TextFilter{ public String process(String s) { return s.toUpperCase(); } } Certified Engineer Course Lookup – Die NetBeans Lösung • Eine kleine von NetBeans unabhängige Bibliothek > Teil des NetBeans org-openide-util.jar > org.openide.util.Lookup • Arbeitet mit jeder Java Version (im Gegensatz zum ServiceLoader) • Ein Lookup ist dynamisch > Listener für Änderungen • Lookups können beliebig instantiiert werden > Erzeuge eines und nutze es • Lookups können kombiniert werden > ProxyLookup vereinigt Lookups und reicht EventNachrichten durch. Certified Engineer Course Ein Lookup ist ein „Aquarium“ für Objekte • Ein „Biotop“ in dem Objekte rein und raus „schwimmen“ • Man erkennt, welche „Arten“ von Objekte hinzukommen oder verschwinden • Mit einem Befehl bekommt man alle Objekte einer „Art“ als Collection Bazz.class Lookup Bar.class Foo.class Certified Engineer Course Nun... Was ist so besonderes daran? ? Was wäre, wenn Objekte Lookups besäßen? Was wäre, wenn Lookups verkettet werden könnten? Certified Engineer Course Objekte, die selbst Lookups besitzen! • TopComponent • Node • DataObject Certified Engineer Course Demo 7: TopComponent Lookup Certified Engineer Course Demo: TopComponent Lookup Gib mir ein SaveCookie SaveAction Editor s s == null ? Ja Nein Deaktiviere die Action Aktiviere die Action interface SaveCookie { void save(); } Bei Aufruf: s.save() Certified Engineer Course Demo 8: TopComponent Lookup private InstanceContent content; ... ... ... content = new InstanceContent(); associateLookup(new AbstractLookup(content)); ... ... content.add(s); Certified Engineer Course Demo 8: TopComponent Lookup private Lookup.Result result; ... ... result = Utilities.actionsGlobalContext().lookupResult(String.class); result.addLookupListener(new LookupListener() { @Override public void resultChanged(LookupEvent e) { textArea2.setText(result.allInstances().toString()); } }); Certified Engineer Course Zusammenfassung • Das Lookup wird an jeder Ecke der NetBeans APIs genutzt • Es wird verwendet für > Die deklarative Registrierung von Global Services > „Instantiation on Demand“ – Reduziert Startzeit > Trennung von API und Implementation − − Ein Modul bietet eine API Ein anderes Modul stellt die Implementation > Kontextsensitivität, z.B., Action-Aktivierung • Es ist nahezu die wichtigste API auf der NetBeans Platform Certified Engineer Course Die Notwendigkeit modularer Anwendungen Certified Engineer Course Die Konzepte im Überblick • • • • • • • • • • • Anwendungsentropie Modularität Abhängigkeits Verwaltung Runtime Container NetBeans Modul NBM Datei API vs. Implementation META-INF/services ServiceLoader vs. Lookup Listener für Lookups Kontextsensitivität mit Lookups Certified Engineer Course Fragen & Antworten http://openide.netbeans.org/lookup/ http://bits.netbeans.org/dev/javadoc/org-openide-modules/overview-summary.html http://openide.netbeans.org/tutorial/api-design.html Certified Engineer Course