Zentrale Aspekte der Komponentenorientierung Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 42 2. JavaBeans als Komponenten • • • • • Java-GUI-Elemente sind Beans Typischer Aufbau von Beans Bound properties Constrained Properties Speichern Literatur: • Sun, JavaBeans 1.01 Specification, http://java.sun.com/ javase/technologies/desktop/javabeans/docs/spec.html • C. Ullenboom, Java ist auch eine Insel, 8. Auflage, Galileo Press [Abschnitt 7.4] Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 53 Hintergrund und Motivation • JavaBeans sind als frühes Komponentenmodell entstanden • Objekte einfach serialisierbar (damit einfach im Netz austauschbar) • Beans-Framework ermöglicht einfache Kommunikation unter Beans • Haupteinsatz: GUI-Komponenten, Swing nutzt Technologie (ermöglicht u. a. GUI-Builder [gute/schlechte]) • Aktuelle Spezifikation: JavaBeans 1.01 • Ideen für JavaBeans Spec 2.0 (JSR-273) existieren • Zitat: “A Java Bean is a reusable software component that can be manipulated visually in a builder tool.” • Achtung: nicht mit Enterprise JavaBeans verwechseln Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 54 Erinnerung : JButton ( Nutzung ) public class ButtonFrame extends JFrame { public ButtonFrame() { setSize(200, 100); JButton rot = new JButton("rot"); rot.addActionListener(new MeineAction(getContentPane(), Color.RED)); add(rot, BorderLayout.EAST); JButton blau = new JButton("blau"); blau.addActionListener(new MeineAction(getContentPane(), Color.BLUE)); add(blau, BorderLayout.WEST); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); } public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() {new ButtonFrame().setVisible(true);} }); } } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 55 Erinnerung : JButton ( ActionListener ) import import import import java.awt.Color; java.awt.Component; java.awt.event.ActionEvent; java.awt.event.ActionListener; public class MeineAction implements ActionListener { private Component komponente; private Color farbe; public MeineAction(Component komponente, Color farbe){ this.komponente = komponente; this.farbe = farbe; } } public void actionPerformed(ActionEvent e) { komponente.setBackground(farbe); } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 56 Typische Beanmethoden ( 1 / 2 ) public class Knopf { public static void main(String[] s){ JButton jb= new JButton(); jb.addPropertyChangeListener(new PCL()); jb.setText("touch me"); jb.setToolTipText("bin ne Bean"); jb.setBackground(Color.red); jb.setBorderPainted(false); JFrame jf = new JFrame(); jf.addPropertyChangeListener(new PCL()); jf.add(jb); jf.setSize(200, 100); jf.setTitle("Knopf"); jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jf.setVisible(true); } } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 57 Typische Beanmethoden ( 2 / 2 ) public class PCL implements PropertyChangeListener{ public PCL() {} public void propertyChange(PropertyChangeEvent evt) { System.out.println(evt.getPropertyName() +" alt:"+evt.getOldValue() +" neu:"+evt.getNewValue()); } text alt: neu:touch me } ToolTipText alt:null neu:bin ne Bean background alt:javax.swing.plaf.ColorUIResource[r=238,... borderPainted alt:true neu:false title alt: neu:Knopf defaultCloseOperation alt:1 neu:3 foreground alt:null neu:java.awt.Color[r=0,g=0,b=0] font alt:null neu:java.awt.Font[family=Dialog,name=Dia... neu:java.awt.Font[family=Dialog,name=Dia... ancestor alt:null neu:javax.swing.JPanel[null.contentP... neu:javax.swing.JPanel[null.contentP... Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 58 Elementare Anforderungen an JavaBean • Leerer Konstruktor • Alle Exemplarvariablen (Properties, Attribute) über get- und set-Methoden erreichbar • Variable private <Typ> xx; public void setXx(<Typ> xx) { this.xx = xx; } public <Typ> getXx() { return xx; } • Methoden können weiteren Code enthalten • Jedwede Typen von Variablen sind serialisierbar Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 59 Minimales Beispiel import java.io.Serializable; public class Student implements Serializable{ private String name; private int cp; public Student(){} public int getCp() { return cp; } public void setCp(int cp) { this.cp = cp; } public String getName() { return name; } public void setName(String name) { this.name = name; } } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 60 Indizierte Eigenschaften • Für Eigenschaften, die in Arrays gespeichert werden, besteht zusätzlich folgende Möglichkeit (Ausschnitt) private String[] vorlesung; public String[] getVorlesung() { //bekannt return vorlesung; } public void setVorlesung(String[] vorlesung) { //bekannt this.vorlesung = vorlesung; } public String getVorlesung(int index) { return vorlesung[index]; } public void setVorlesung(String vl, int index) { vorlesung[index]=vl; } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 61 Einschub : typischer schlechter Stil • Arrays sind für dynamische Datenmengen unflexibel • Collections sind zum Glück serialisierbar private Set<String> vorlesung= new HashSet<String>(); • In JavaBeans können weitere Methoden ergänzt werden public void weitereVorlesung(String v){ vorlesung.add(v); } • Leider nicht unüblich der Stil „Innereien herausreißen, verändern, Innereien wieder hinschieben“ (verletzt eigentlich Geheimnisprinzip) Student st = new Student(); st.getVorlesung().add("KomSE"); Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 62 Gebundene Eigenschaften • Bound properties sind Exemplarvariablen, die Änderungen interessierten Beans mitteilen (Observer-Observable) • Wer Änderungen mitteilen will, – benötigt Objekt der Klasse PropertyChangeSupport – muss Methoden add/removePropertyChangeListener implementieren • Interessenten für Änderungen müssen sich mit add… anmelden • Bei Anmeldung muss Objekt übergeben werden, das das Interface PropertychangeEvent implementiert Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 63 Beispiel- Erweiterung in Student ( 1 / 2 ) import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; … private PropertyChangeSupport pcs=new PropertyChangeSupport(this); public void setCp(int cp) { int alt=this.cp; this.cp = cp; pcs.firePropertyChange("cp", alt, cp); } public void addPropertyChangeListener(PropertyChangeListener l){ pcs.addPropertyChangeListener(l); } public void removePropertyChangeListener( PropertyChangeListener l){ pcs.removePropertyChangeListener(l); } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 64 Beispiel- Erweiterung in Student ( 2 / 2 ) import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; public class Studentnutzer { public static void main(String[] args) { Student s = new Student(); s.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent e) { System.out.println("Eigenschaft "+e.getPropertyName() +" alt:"+e.getOldValue()+" neu:"+e.getNewValue()); } }); s.setCp(42); s.setCp(s.getCp()+5); s.setCp(47); Eigenschaft cp alt:0 neu:42 } Eigenschaft cp alt:42 neu:47 } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 65 Veto - Eigenschaften • Spezielle Möglichkeit von JavaBeans: Vetoable (constrained) – Bean meldet angemeldeten Beans, dass eine Exemplarvariable geändert wird – Jede Bean kann „Einspruch“ gegen die Änderung (PropertyVetoException) einlegen • Konkretes Szenario: Kundenbestellung soll durchgeführt werden, Kontoverwaltung und Lagerverwaltung lauschen und können Einspruch einlegen • Schwierig, Daten konsistent zu halten (wer kein Veto einlegt, rechnet weiter); deshalb erst nach Vetos fragen (keiner rechnet weiter), dann als gebundene Eigenschaft propagieren • Nach Einspruch werden alle angemeldeten Beans erneut mit altem Wert informiert Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 66 Beispiel ohne Bound Property ( 1 / 3 ) private VetoableChangeSupport vcs=new VetoableChangeSupport(this); public void setVorlesung(Set<String> vorlesung) { Set<String> old = this.vorlesung; in Student try { vcs.fireVetoableChange("vl", old, vorlesung); this.vorlesung = vorlesung; } catch (PropertyVetoException ex) { System.out.println("abgelehnt: "+ex.getMessage()); } } public void addVetoableChangeListener(VetoableChangeListener l){ vcs.addVetoableChangeListener(l); } public void removeVetoableChangeListener( VetoableChangeListener l) { vcs.removeVetoableChangeListener(l); } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 67 Beispiel ohne Bound Property ( 2 / 3 ) public class MeinVeto implements VetoableChangeListener{ private String schlecht; private int aenderung; public MeinVeto(String schlecht) { this.schlecht = schlecht; } @Override public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { Set<String> neu = (Set<String>) evt.getNewValue(); if (neu.contains(schlecht)) throw new PropertyVetoException("nicht "+schlecht, evt); System.out.println("für "+schlecht+": "+(++aenderung)); } } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 68 Beispiel ohne Bound Property ( 3 / 3 ) public static void main(String[] args) { Student stu = new Student(); Set<String> vls = new HashSet(); vls.add("C"); vls.add("Java"); stu.addVetoableChangeListener(new MeinVeto("BWL")); stu.addVetoableChangeListener(new MeinVeto("C++")); stu.setVorlesung(vls); Set<String> tmp = (Set<String>)vls.clone(); für BWL: 1 tmp.add("C++"); für C++: 1 stu.setVorlesung(tmp); System.out.println(stu.getVorlesung()); für BWL: 2 } für BWL: 3 für C++: 2 abgelehnt: nicht C++ [C, Java] Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 69 Einfaches Speichern ( von JavaBeans ) public static void main(String[] args) { Student stu = new Student(); HashSet<String> vls = new HashSet(); vls.add("C"); vls.add("Java"); stu.setVorlesung(vls); stu.setName("Erwin"); try { XMLEncoder out = new XMLEncoder(new BufferedOutputStream( new FileOutputStream("stu.xml"))); out.writeObject(stu); out.close(); XMLDecoder in= new XMLDecoder(new BufferedInputStream( new FileInputStream("stu.xml"))); Student st= (Student)in.readObject(); System.out.println(st.getVorlesung()); in.close(); } catch (FileNotFoundException ex) { } [C, Java] } Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 70 stu.xml <?xml version="1.0" encoding="UTF-8"?> <java version="1.6.0_12" class="java.beans.XMLDecoder"> <object class="beans.Student"> <void property="name"> <string>Erwin</string> </void> <void property="vorlesung"> <void method="add"> <string>C</string> </void> <void method="add"> <string>Java</string> </void> </void> </object> </java> Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 71 Analyse des Beispiels • Wesentliche Funktionalität wurde an Java (genauer die Virtual Machine VM) abgegeben; diese arbeitet als Container • VM kann direkt auf Exemplarvariablen zugreifen (Ansätze mit Introspection, Reflection evtl. später) – Gib mir Exemplarvariablen – Gib mir Exemplarmethoden – (Textanalyse, Beginn mit get/set) – Rufe auf Objekt mit Methode mit Namen … und Parametern … auf Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 72 Weiterführend • Zu jeder Bean kann es eine BeanInfo-Klasse geben, die die Bean beschreibt • Ursprünglich sind Beans für visuelle Komponenten entwickelt worden; GUIBuilder erlauben die direkte Bearbeitung von Properties • Java-Bean für GUI-Builder in jar-Datei mit Manifest-Datei (.mf) • Es gibt eigene Werkzeuge zur Entwicklung mit Beans Komponentenbasierte Software- Entwicklung Prof. Dr. Stephan Kleuker 73