Eigenschaften, sog. Properties, sind die wichtigsten Elemente einer JavaBeans-Komponente. Nach der JavaBeans-Spezifikation werden die Eigenschaften entweder als private oder als protected deklariert. Allerdings existieren zu jeder Eigenschaft, die nach außen hin sichtbar sein muss, die entsprechenden Getter- und Setter-Methoden. Der Grund hierfür liegt in der Kapselung (Information Hiding) eines Beans. Ein Bean soll der Außenwelt lediglich als einfache Black-Box erscheinen. Eigenschaften dienen in erster Linie dazu, einem Bean interaktiv zur Laufzeit Parameter übergeben zu können. Da Properties aber als Methoden implementiert sind, stehen dem Entwickler zusätzliche Möglichkeiten zur Auswertung zur Verfügung. Die Methoden von Properties entsprechen in ihrer Bedeutung den als public deklarierten Methoden einer gewöhnlichen Java-Klasse. Durch die Veränderung von Eigenschaften können Anwendungsentwickler das Erscheinungsbild und das Verhalten eines JavaBeans beeinflussen. Innerhalb der schreibenden set-Methode kann vor einer Veränderung eines Wertes eine Prüfung des alten bzw. des zu setzenden neuen Wertes erfolgen, aus der weitere Aktionen resultieren können. Bei den Eigenschaften wird zwischen Indexed-, Bound-, und Constrained-Properties unterschieden. Eigenschaften können in zwei Kategorien klassifiziert werden: In passive Eigenschaften und aktive Eigenschaften. Passive Eigenschaften Passive Eigenschaften sind diejenigen Eigenschaften, die mit keinem EventListener-Objekt verbunden sind. Somit wirkt sich eine Änderung einer dieser Eigenschaften nur auf die entsprechende Eigenschaft, bzw. auf das Bean, das von dieser Eigenschaft abhängt, aus. Ein Beispiel hierfür ist das Ändern der Hintergrundfarbe eines Beans. Zu den passiven Eigenschaften zählen sowohl einfache Eigenschaften als auch indizierte Eigenschaften (Indexed Properties). Bei indizierten Eigenschaften wird in der get/set-Methode ein int-Parameter als Index für das Datenfeld hinzugefügt: public setWertInFeld(int index, int wert); public getWertInFeld(int index); Einfache Eigenschaften Einfache Eigenschaften repräsentieren einen einzelnen Wert. Sie sind typischerweise interne Variablen, die man durch Getter- und Setter-Methoden ansprechen kann. Eine Getter-Methode beginnt immer mit einem get, gefolgt vom Namen der Eigenschaft. Der Wert einer Eigenschaft kann durch eine Setter-Methode geändert werden. Eine Setter-Methode beginnt mit einem set, gefolgt vom Namen einer Eigenschaft. Die Existenz der Getter- und Setter-Methode impliziert, dass die Eigenschaft les- und schreibbar ist. Wenn eine Variable innerhalb eines Beans nicht veränderbar sein darf, gibt es folglich auch keine Setter-Methode. Eine Eigenschaft kann auch nicht lesbar sein, wenn keine Getter-Methode existiert. Bei boole'schen Variablen kann die Getter-Methode durch eine is-Methode ersetzt werden. Eine is-Methode beginnt mit einem is, gefolgt vom Namen einer Eigenschaft. Nachfolgend ist ein Beispiel angeführt, das das Arbeiten mit einfachen Eigenschaften verdeutlicht. Hierbei handelt es sich um Schüler mit zwei Eigenschaften, Alter und Familienstand (ausgedrückt durch die boole'sche Variable verheiratet). public class Schueler implements Serializable{ private int alter; private boolean verheiratet; // Null-Konstruktor Schueler(){ } // Die Lesemethode der Eigenschaft Alter public int getAlter(){ return alter; } // Die Schreibmethode der Eigenschaft Alter public void setAlter(int dasAlter){ alter = dasAlter; } // Die Lesemethode der Eigenschaft verheiratet public boolean isVerheiratet(){ return verheiratet; } // Die Schreibemethode der Eigenschaft verheiratet public setVerheiratet(boolean status){ verheiratet = status; } } Indizierte Eigenschaften Indizierte Eigenschaften (Indexed Properties) verwalten mehrere Eigenschaften, die denselben Datentyp haben. Mit den üblichen Getter- und Setter-Methoden wird die Menge der Eigenschaften in einem Schritt als Array zurückgegeben. Die Möglichkeit, die Eigenschaft eines einzelnen Elements dieser Menge zu verändern bzw. zu lesen, ist durch einen indizierten Array gegeben. Das folgende Beispiel, das eine Liste von Lehrern verwaltet, soll dieses Vorgehen verdeutlichen. public class MeineLehrer { private String lehrer[]; // Konstruktor fuer die Klasse MeineLehrer(String[] lehrerListe){ lehrer = lehrerListe; } // Die Lesemethode fuer einen Lehrer an einer bestimmten // Stelle der Liste. public Stirng getLehrer(int index){ return lehrer[index]; } // Die Schreibmethode fuer einen Lehrer an einer bestimmten // Stelle der Liste. public void setLehrer(int index, String lehrerX){ lehrer[index] = lehrerX; } // Die Lesemethode der kompletten Liste public Stirng[] getLehrer(){ return lehrer; } } Wenn Zugriffe auf Bereiche außerhalb der Grenzen eines indizierten Arrays von Eigenschaften erfolgen, meldet die entsprechende Zugriffsmethode die Exception ArrayIndexOutOfBoundsException. Dieses Verhalten stimmt mit dem regulären Verhalten von Java bei der Indizierung außerhalb von Array-Grenzen überein. Aktive Eigenschaften In diesem Abschnitt wird erläutert, wie eine einfache Eigenschaft erweitert werden kann, um Objekte über eine Zustandsänderung zu benachrichtigen. Gebundene Eigenschaften (Bound-Properties) eines Beans kombinieren die Verwaltung von Eigenschaften mit dem Event-Mechanismus. Beans informieren bspw. andere registrierte Komponenten über die Änderung einer ihrer Eigenschaften. Die registrierten Beans empfangen dann einen entsprechenden Event und können geeignet auf die Änderung reagieren. Dieses Konzept wird durch Constrained-Eigenschaften (Constrained-Properties) noch erweitert. Diese ermöglichen es, eine beabsichtigte Wertänderung von einer anderen Komponente prüfen zu lassen. Die Änderung des Beans darf nur erfolgen, wenn keine externe Komponente die Änderung verhindert. JavaBeans kommunizieren über Events miteinander. Die Klasse java.util.EventObject dient als Basisklasse für die versendeten Events. Die Implementierung verwendet hierbei das Event-Modell von JDK 1.1 mit Event-Quellen und Event-Listenern. Im Folgenden werden Bound- und Constrained-Eigenschaften detailliert betrachtet. Bound -Properties Gebundene Eigenschaften (Bound Properties) sind Eigenschaften, die einen Benachrichtigungsmechanismus beinhalten, der Änderungen anzeigt, die an Eigenschaften selbst durchgeführt werden. Externe Beans, Applets oder Anwendungen, die benachrichtigt werden wollen, wenn eine Änderung der Eigenschaft auftritt, registrieren sich bei der gebundenen Eigenschaft (Funktion als Event-Listener). Gebundene Eigenschaften informieren Event-Listener über Änderungen, indem sie einen PropertyChangeEvent auslösen. Ähnlich wie bei Events stellt ein Bean mit gebundenen Eigenschaften die folgenden Methoden für die Registrierung von Event-Listenern zur Verfügung: addPropertyChangeListener(PropertyChangeListener l); removePropertyChangeListener(PropertyChangeListener l); Wird ein Event ausgelöst, so generiert die Methode firePropertyChange() der Klasse PropertyChangeSupport einen Event vom Typ PropertyChangeEvent und leitet diesen an alle Listener weiter. Das Objekt PropertyChangeEvent enthält den Namen des Quell-Beans und den alten sowie den neu zu setzenden Wert der Eigenschaft. Abb. 9-10 veranschaulicht die Vorgehensweise bei der Änderung einer Bound-Property. Abb. 9.10: Vorgehensweise bei der Änderung einer Bound-Eigenschaft Constrained-Properties Durch gebundene Eigenschaften (Bound Properties) werden registrierte Komponenten über Änderungen einer Eigenschaft benachrichtigt. Eine Erweiterung hierzu sind die eingeschränkten Eigenschaften (Constrained-Properties), Eigenschaften, die registrierte Komponenten über Änderungen benachrichtigen und es ihnen gleichzeitig ermöglichen, eine Änderung abzulehnen und diese somit rückgängig zu machen. Wird eine Änderung einer Eigenschaft rückgängig gemacht, so muss das Bean allen registrierten Komponenten nochmals eine Nachricht mit dem alten Wert der Eigenschaft senden. Der Mechanismus, eine eingeschränkte Eigenschaft mit den registrierten Komponenten zu verbinden, ähnelt dem von gebundenen Eigenschaften. Auch hier werden Methoden zur Registrierung benutzt, nur dass diese nicht das Interface PropertyChangeListener benutzen, sondern das Interface VetoableChangeListener. public void addVetoableChangeListener(VetoableChangeListener l); public void removeVetoableChangeListener(VetoableChangeListener l); Weiterhin sollte die Schreibmethode (set-Methode) dieser Eigenschaft eine PropertyVetoException auswerfen, wodurch erkannt werden kann, dass es sich bei dieser Eigenschaft um eine eingeschränkte Eigenschaft handelt. // Definition einer-Getter Methode fuer eine // Constrained-Property public int getAlter(){ return alter; } // Definition einer-Setter Methode fuer eine // Constrained-Property, die wirft ein // PropertyVetoException auswirft public void setAlter(int dasAlter) throws PropertyVetoException { alter = dasAlter; } Ähnlich wie bei gebundenen Eigenschaften veranschaulicht Abb. 9-11 die Vorgehensweise bei der Änderung einer Constrained-Property. Wie bei gebundenen Eigenschaften sendet das betroffene Bean eine Benachrichtigung über eine Eigenschaftsänderung an ein EventListener-Objekt. Das EventListener-Objekt hat jedoch in diesem Fall die Möglichkeit, die Änderung der entsprechenden Eigenschaft abzulehnen, indem es die Ausnahmemeldung PropertyVetoException als Rückgabewert liefert. Wenn eine derartige Ausnahmemeldung erzeugt wird, muss das Bean derart fortfahren, dass der alte Wert der Eigenschaft wieder hergestellt wird und alle EventListener-Objekte davon in Kenntnis gesetzt werden. Die Methode für eingeschränkte Eigenschaften lautet VetoableChangeEvent(), die Benachrichtigung, die versendet wird, ist allerdings dieselbe (PropertyChangeEvent-Objekt). Abb. 9.11: Vorgehensweise bei der Änderung einer Constrained-Eigenschaft Das folgende Beispiel verdeutlicht die Verwendung von gebundenen und von eingeschränkten Eigenschaften. Während das Attribut Farbe hierbei als gebundene Eigenschaft verwendet wird, ist das Attribut Preis eine eingeschränkte Eigenschaft. Im Beispiel werden Instanzen der Klassen PropertyChangeSupport- und VetoableChangeSupport verwendet, um aktuelle Ereignisse zu senden. import java.awt.*; import java.beans.*; public class myBean1 { private PropertyChangeSupport changes = new PropertyChangeSupport(this); private VetoableChangeSupport vetos = new VetoableChangeSupport(this); private Color farbe = Color.blue; private int preis = 2; public Color getFarbe() { return farbe; } Die Setter-Methode löst einen PropertyChangeEvent aus, um die registrierten Komponenten zu benachrichtigen. public void setFarbe(Color neueFarbe) { Color alteFarbe = farbe; farbe = neueFarbe; changes.firePropertyChange("farbe", alteFarbe, neueFarbe); } public int getPreis() { return preis; } public void setPreis(int neuerPreis) throws PropertyVetoException { int alterPreis = Preis; Zuerst werden die registrierten Komponenten über die Änderung benachrichtigt, anschließend erfolgt das Schreiben des neuen Wertes. vetos.fireVetoableChange("preis", new Integer(alterPreis), new Integer(neuerPreis)); // Kein Veto zurückgekommen, // dann kann die Änderung erfolgen preis = neuerPreis; changes.firePropertyChange("preis", new Integer(alterPreis), new Integer(neuerPreis)); } Die Methoden zum An- bzw. Abmelden der EventListener-Objekte sehen wie folgt aus. public void addPropertyChangeListener(PropertyChangeListener l) { changes.addPropertyChangeListener(l); } public void removePropertyChangeListener(PropertyChangeListener l) { changes.removePropertyChangeListener(l); } public void addVetoableChangeListener(VetoableChangeListener l) { vetos.addVetoableChangeListener(l); } public void removeVetoableChangeListener(VetoableChangeListener l) { vetos.removeVetoableChangeListener(l); } } API-Unterstützung Im Folgenden werden die wichtigsten Klassen und Methoden des Packages java.beans erläutert, die für Eigenschaften von Bedeutung sind. Klasse PropertyChangeEvent public class java.beans.PropertyChangeEvent extendsjava.util.EventObject Beans können diesen Event-Typ an registrierte PropertyChangeListener senden, um diese über die Änderung einer gebundenen (bound) oder eingeschränkten (constrained) Eigenschaft zu informieren. Der Event wird als Argument der Methoden PropertyChangeListener und VetoableChangeListener verwendet. PropertyChangeEvent-Objekte werden zusammen mit dem Namen der Eigenschaft, deren alten und deren neuen Wert gesendet. Diese Klasse verwendet den folgenden Konstruktor: public PropertyChangeEvent(Object source, String propertyName,Object oldValue, Object newValue) Die Parameter haben hierbei die folgende Bedeutung: source : Quell-Bean propertyName: Name der Eigenschaft, die geändert wurde oldValue: Alter Wert der Eigenschaft newValue: Neuer Wert der Eigenschaft Die Methoden, die Teil der Klasse PropertyChangeEvent sind, lauten: Object getNewValue() und Object getOldValue() liefern den neuen bzw. den alten Wert der Property als Objekt zurück. Dieser Wert kann null sein, wenn mehrere Eigenschaften geändert wurden. String getPropertyName() liefert den Namen der Eigenschaft zurück, die geändert wurde. Interface PropertyChangeListener public interface java.beans.PropertyChangeListener extendsjava.util.EventListener Ein PropertyChange-Event wird ausgelöst, wenn eine gebundene Eigenschaft eines Beans geändert wird. Diese Schnittstelle verwendet eine einzige Methode: propertyChanged(PropertyChangeEvent evt) wird aufgerufen, wenn eine Eigenschaft geändert wird. Als Parameter wird ein Objekt übergeben, das die Event-Quelle und die geänderte Eigenschaft beschreibt. Klasse PropertyChangeSupport public class java.beans.PropertyChangeSupport extends java.lang.Object implements java.io.Serializable Der Konstruktor dieser Klasse lautet wie folgt: public PropertyChangeSupport(Object sourceBean) Folgende Methoden sind Teil dieser Klasse: addPropertyChangeListener(PropertyChangeListener listener) und removePropertyChangeListener(PropertyChangeListener listener): Diese Methoden werden zum Hinzufügen eines PropertyChangeListener-Objektes bzw. zum Entfernen aus der EventListener-Liste verwendet. firePropertyChange(String propertyName, Object oldValue, Object newValue) löst einen Event aus, wenn sich eine gebundene Eigenschaft ändert. Falls der alte Wert der Eigenschaft dem neuen Wert entspricht, wird kein Event generiert. Klasse PropertyVetoException public class java.beans.PropertyVetoException extends java.lang.Exception Eine PropertyVetoException wird ausgelöst, wenn die Änderung einer Eigenschaft von einem EventListener-Objekt nicht akzeptiert wird. Der Konstruktor dieser Klasse lautet wie folgt: PropertyVetoException(String message,PropertyChangeEvent evt) Diese Klasse verwendet die folgende Methode: PropertyChangeEvent getPropertyChangeEvent() liefert einen Event zurück Interface VetoableChangeListener public interface java.beans.VetoableChangeListener extends java.util.EventListener Ein PropertyChangeEvent wird ausgelöst, wenn eine eingeschränkte Eigenschaft eines Beans geändert wird. Diese Schnittstelle verwendet eine einzige Methode, die aufgerufen wird, wenn eine Eigenschaft geändert wird: public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException Klasse VetoableChangeSupport public class java.beans.VetoableChangeSupport extends java.lang.Object implements java.io.Serializable Der Konstruktor dieser Klasse lautet wie folgt: public VetoableChangeSupport(Object sourceBean) Folgende Methoden sind Teil dieser Klasse: addVetoableChangeListener(VetoableChangeListener listener) und removeVetoableChangeListener(VetoableChangeListener listener) Diese Methoden werden zum Hinzufügen eines VetoableChangeListener-Objektes bzw. zum Entfernen aus der EventListener-Liste verwendet. fireVetoableChange(String propertyName, Object oldValue, Object newValue) throws PropertyVetoException Diese Methode generiert einen Event, wenn sich eine eingeschränkte Eigenschaft ändert. Falls der alte Wert der Eigenschaft dem neuen Wert entspricht, wird kein Event ausgelöst. Zusammenfassung Eigenschaften sind mit gekapselten Daten innerhalb von Klassen vergleichbar. Eine von vielen Standardeigenschaften visueller Beans ist z. B. deren Hintergrundfarbe. Durch die Zuweisung eines neuen Wertes aus einem Programm heraus oder durch ein interaktives Fensters übernimmt das Bean die übergebene Einstellung und zeigt sie sofort an. Nachdem die passiven Eigenschaften (einfache Eigenschaften) erklärt wurden, wurde die komplexere Struktur der aktiven Eigenschaften (Bound- und Constrained-Properties) erläutert. Der Umgang mit diesen Eigenschaften sowie deren Nutzen wurde anschließend verdeutlicht.