Der vollständige Temperaturregelungs

Werbung
8.
8.1
Der vollständige Temperaturregelungs-Simulator
Definition des Simulators
Der vollständige TemperaturregelungsSimulator
• Wir haben bisher die grundlegenden Konzepte von JavaBeans
behandelt.
• Nun können wir die Einzelbeispiele zu einem Ganzen
zusammensetzen.
• Danach beschäftigen wir uns mit weiteren spezielleren Themen der
JavaBeans anhand dieser Beispiele.
• Wir wollen einen Simulator erstellen, der unsere Temperaturquelle
und das Thermometer kombiniert.
Definition des Simulators
Grobe Anforderungsdefinition:
• Der Simulator soll die Umgebungstemperatur des Systems
überwachen und ändern.
• Es wird ein Mechanismus benötigt, die Wunschtemperatur
einstellen zu können.
• Die Umgebungstemperatur soll in Celsius und in Fahrenheit
dargestellt werden können.
• Die ganze Simulation muß serialisierbar sein.
Daraus ergeben sich die folgenden Anforderungen für die wichtigsten
Komponenten des Simulators.
- 169
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.1
Der vollständige Temperaturregelungs-Simulator
Definition des Simulators
Temperatur Objekt
• Es stellt die Umgebungstemperatur dar. Die anderen Komponenten
des Simulators überwachen es oder ändern seine Temperatur.
• Der Wert der Temperatur muß, am besten durch ein anders Objekt
(Thermostat), darstellbar sein.
• Andere Objekte müssen die Anforderung stellen können, die
Temperatur zu ändern.
Thermostat Objekt
• Es stellt dem Anwender die Temperatur in Celsius oder Fahrenheit
dar.
• Der Anwender kann mit Hilfe des Thermostats die
Wunschtemperatur eingeben, ebenfalls in Celsius oder Fahrenheit.
• Da das Thermostat Objekt die augenblickliche
Umgebungstemperatur und die Wunschtemperatur des Anwenders
kennt, weiß es auch, ob die Umgebungstemperatur verändert
werden muß.
- 170
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.1
Der vollständige Temperaturregelungs-Simulator
Definition des Simulators
Heiz- und Kühl-Objekte
• Diese Objekte verändern die Umgebungstemperatur.
- Jedes der Objekte hat eine bestimmte Temperatur.
- Wenn sie arbeiten, senden sie in bestimmten Abstände Impulse
mit ihrer Temperatur aus.
• Sie wissen nicht selbst, wann sie aktiv sein müssen. Stattdessen
hängen sie von anderen Objekten ab, die ihnen sagen, wann sie
laufen müssen.
Ereignisse
• Der Thermostat weiß, wann Ist- und Soll-Temperatur differieren.
- Also muß er das Heiz- oder Kühl-Objekt starten.
- Ist die gewünschte Temperatur erreicht, muß er das Objekt wieder stoppen.
• Wenn das Heiz- oder Kühl-Objekt läuft, sendet es TemperaturImpulse in festen Intervallen aus. Das Temperatur-Objekt reagiert
darauf.
• Andererseits muß der Thermostat wissen, wenn das TemperaturObjekt seine Eigenschaft ändert, damit er diese anzeigen und ggf.
Heiz- oder Kühl-Objekt kontrollieren kann.
Thermostat
Temperature
Change
Request Service
Turned On or Off
Temperature
Temperature Pulse
Heating or Cooling Device
- 171
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Implementierung des Simulators
Wir beginnen mit den Event-Klassen (keien Abhängigkeiten von
anderen Klassen des Systems).
Dann Listeners-Interfaces.
Dann die Klassen der aktiven Objekte.
Temperatur-Impuls Events
package BeansBook.Simulator;
// class definition for the temperature pulse event
public class TemperaturePulseEvent
extends java.util.EventObject {
// the pulse temperature
protected double theTemp;
// constructor
public TemperaturePulseEvent(Object source, double t) {
// pass the source to the superclass
super(source);
}
}
// save the temperature
theTemp = t;
// return the pulse temperature
public double getPulseTemperature() {
return theTemp;
}
Um solche Ereignisse empfangen zu können, muß eine Klasse die
Schnittstelle TemperaturePulseListener implementieren:
- 172
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
TemperaturePulseListener Interface
package BeansBook.Simulator;
// interface for temperature pulse listener
public interface TemperaturePulseListener
extends java.util.EventListener {
}
// event handler method for temperature pulse
public void temperaturePulse(TemperaturePulseEvent evt);
Service Request Events
Läßt ein Gerät (Heiz- oder Kühlgerät) sich an- oder abschalten:
package BeansBook.Simulator;
// the service request event class
public class ServiceRequestEvent
extends java.util.EventObject {
// true if the request is to start the service
protected boolean bStart;
// constructor
public ServiceRequestEvent(Object source, boolean start) {
// call the superclass constructor
super(source);
}
// save the value of the start flag
bStart = start;
// determine if the request is to start the service
public boolean isStart() {
// return the start value
return bStart;
}
}
Wird Thermostat erzeugt und geschickt, wenn dieser feststellt, daß
zwischen Ist- und Soll-Temperatur ein Unterschied herrscht.
- 173
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Listener Schnittstellen
Zwei verschiedene Listener-Schnittstellen, eine für das Heizgerät und
eine für das Kühlgerät.
Damit ist der Empfänger sicher, daß er nur die für ihn bestimmten
Ereignisse erhält.
package BeansBook.Simulator;
// the interface definition for heating request listeners
public interface HeatingRequestListener
extends java.util.EventListener {
// the heating request event handler
public void heatingRequest(ServiceRequestEvent evt);
}
// the interface definition for cooling request listeners
public interface CoolingRequestListener
extends java.util.EventListener {
// the cooling request event handler
public void coolingRequest(ServiceRequestEvent evt);
}
Der Ereignistyp ist in beiden Fällen derselbe.
- 174
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Property Change Events
• Die Temperature Eigenschaft des Temperature Objektes ist als
bound property sinnvoll.
- So kann z.B. der Thermostat von jeder Änderung erfahren.
• Auch eine constrained property ist nützlich.
- Es ist nicht sinnvoll, daß die Solltemperatur höher eingestellt
wird, als das Heizgerät als eigene Temperatur hat.
- Falls das versucht wird, muß das Heiz-Objekt ein Veto einlegen.
- 175
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Klasse Temperature (1/3)
Repräsentiert die Umgebungstemperatur (Ist-Temperatur):
package BeansBook.Simulator;
import java.beans.*;
// the temperature bean class definition
public class Temperature
implements TemperaturePulseListener,
// listens for temperature pulses
java.io.Serializable
// declare Serializable {
// support object for bound property listeners
protected PropertyChangeSupport boundSupport;
// the current temperature
protected double theTemperature = 22.0;
// constructor
public Temperature() {
// construct the support object
boundSupport = new PropertyChangeSupport(this);
}
// add a property change listener
public void addPropertyChangeListener(
PropertyChangeListener l) {
// defer to the support object
boundSupport.addPropertyChangeListener(l);
}
// remove a property change listener
public void removePropertyChangeListener(
PropertyChangeListener l) {
// defer to the support object
boundSupport.removePropertyChangeListener(l);
}
- 176
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Klasse Temperature (2/3)
// get the value of the Temperature property
public double getTemperature() {
return theTemperature;
}
// set the value of the Temperature property
public void setTemperature(double t) {
// don't bother if the value didn't change
if (t == theTemperature)
return;
// save the old value
Double old = new Double(theTemperature);
// save the new value
theTemperature = t;
}
// fire the property change event
boundSupport.firePropertyChange("Temperature",
old, new Double(t));
- 177
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Klasse Temperature (3/3)
// handle a temperature pulse event
public void temperaturePulse(TemperaturePulseEvent evt) {
// get the pulse temperature
double p = evt.getPulseTemperature();
// get the current temp
double c = getTemperature();
}
}
// if the pulse temperature is greater than the
// current temperature
if (p > c) {
// only change if the difference is more than 1
if ((p - c) >= 1.0) {
// add 1 to the current temperature
setTemperature(c + 1.0);
}
}
else if (p < c) {
// pulse less than current temp
// only change if the difference is more than 1
if ((c - p) >= 1.0) {
// subtract 1 from the current temperature
setTemperature(c - 1.0);
}
}
- 178
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Heiz- und Kühl-Klassen (1/7)
• Verhalten sich identisch.
- Besitzen nur unterschiedliche Temperaturen.
- Wir verwenden eine Basisklasse TemperatureModifier.
- Sämtliches gemeinsames Verhalten wird hier implementiert.
- Später spezialiseren wir zu Heiz- und Kühl-Klassen.
• Um Instanzen dieser Klassen darstellen zu können, konstruieren
wir sie als Nachfahren von Label.
• Da wir unterschiedliche Threads für diese Klassen haben möchten,
implemetieren sie das Interface Runnable.
• Bei der Serialisierung müssen wir selbst eingreifen: Wir müssen den
Thread nach der Wiederherstellung neu starten und die Listener
müssen sorgfältig behandelt werden.
- 179
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Heiz- und Kühl-Klassen (2/7)
package BeansBook.Simulator;
import
import
import
import
java.awt.*;
java.beans.*;
java.io.*;
java.util.*;
// class definition for the temperature modifier
public abstract class TemperatureModifier
extends Label
implements Runnable {
// a thread to send temperature pulses
protected transient Thread thrd;
// the temperature pulse listener
protected transient TemperaturePulseListener listener
= null;
// the running state
protected boolean running = false;
// the rate (in msecs) that pulses are generated
protected int rate = 1000;
// the text to use when running
protected String onText;
// the text to use when not running
protected String offText;
// the color to use when running
protected Color onColor;
// the color to use when not running
protected Color offColor;
// the pulse temperature
protected double temp;
- 180
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Heiz- und Kühl-Klassen (3/7)
public TemperatureModifier(double tmp, String onT,
String offT, Color onC, Color offC) {
// start the label out with the text for not running
super(offT);
// save the operating temperature
temp = tmp;
// save the various text and color values
onText = onT;
offText = offT;
onColor = onC;
offColor = offC;
setBackground(offColor);
// set text alignment to center
setAlignment(Label.CENTER);
}
// start the pulse thread
startThread();
// start the pulse thread
private void startThread()
{
// create and start the pulse thread
thrd = new Thread(this);
thrd.start();
}
- 181
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Heiz- und Kühl-Klassen (4/7)
// write the state of the object
private void writeObject(ObjectOutputStream stream)
throws IOException {
// defer to the default process
stream.defaultWriteObject();
// Handle serializing of listeners
// get a copy
TemperaturePulseListener lstnr = null;
synchronized (this) {
lstnr = listener;
}
boolean bWriteNull = (lstnr == null);
if (!bWriteNull) {
// is it serializable?
if (lstnr instanceof Serializable) {
stream.writeObject(lstnr);
}
else {
// write a null to the stream
bWriteNull = true;
}
}
}
// should we write a null?
if (bWriteNull) {
stream.writeObject(null);
}
- 182
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Heiz- und Kühl-Klassen (5/7)
// read the state of the object
private void readObject(ObjectInputStream stream)
throws IOException
try {
// defer to the default process
stream.defaultReadObject();
{
// read back the listener
Object obj;
while(null != (obj = stream.readObject())) {
addTemperaturePulseListener(
(TemperaturePulseListener)obj);
}
// start the pulse thread
startThread();
}
}
catch (Exception e) {
System.out.println(e);
}
// set the value of the Rate property
public void setRate(int r) {
rate = r;
}
// get the value of the Rate property
public int getRate() {
return rate;
}
- 183
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Heiz- und Kühl-Klassen (6/7)
// set the value of the Running property
public synchronized void setRunning(boolean b) {
// don't bother if there is no change
if (running == b) {
return;
}
// save the new value
running = b;
}
// set the appropriate label text and background color
if (running) {
setText(onText);
setBackground(onColor);
}
else {
setText(offText);
setBackground(offColor);
}
// get the value of the Running property
public boolean isRunning() {
return running;
}
// add a unicast temperature pulse listener
public synchronized void
addTemperaturePulseListener(TemperaturePulseListener l)
throws TooManyListenersException {
// if there is already a listener, throw an exception
if (listener != null) {
throw new TooManyListenersException();
}
}
// store the listener
listener = l;
- 184
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Heiz- und Kühl-Klassen (7/7)
// remove the unicast temperature pulse listener
public synchronized void
removeTemperaturePulseListener(
TemperaturePulseListener l) {
// make sure this is the listener we have
if (listener == l) {
listener = null;
}
}
// the run method for the pulse thread
public void run() {
// loop forever
while(true) {
try {
// sleep for the time specified by rate
thrd.sleep(rate);
// if there is a listener and the service is
// running, then send the pulse event
if (listener != null && running) {
listener.temperaturePulse(
new TemperaturePulseEvent(this, temp));
}
}
}
}
}
catch (Exception e) {
}
- 185
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Klasse Cooler
• Nun können wir den Cooler als Nachfahren implementieren.
- Zusätzlich muß die Schnittstelle CoolingRequestListener implementiert werden.
- Weiterhin muß die VetoableChangeListener Schnittstelle implementiert werden, damit der Anwender keine Temperatur angibt,
die niedriger als die des Kühlgerätes ist.
- Das VetoableChangeEvent kommt vom Thermostaten, wenn der
Anwender die Solltemperatur ändert.
• Der Cooler arbeitet mit einer Temperatur von 0° C.
- 186
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Cooler Implementierung
package BeansBook.Simulator;
import java.awt.*;
import java.beans.*;
// the Cooler bean class definition
public class Cooler extends TemperatureModifier
implements CoolingRequestListener,
VetoableChangeListener
{
// constructor
public Cooler() {
// a cooler is a temperature modifier that operates at
// 0 degress celsius
super(0.0, "COOLER ON", "COOLER OFF",
Color.cyan, Color.yellow);
}
// handle a cooling request event
public void coolingRequest(ServiceRequestEvent evt) {
// set the Running property based on the value returned
// by the isStart method from the event
setRunning(evt.isStart());
}
// handle a vetoable change event
public void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException {
// only interested in ComfortTemperature
if (evt.getPropertyName().equals(
"ComfortTemperature")) {
// get the proposed temperature
Double d = (Double)evt.getNewValue();
}
}
// veto a temperature under 0 degrees Celsius
if (d.doubleValue() < 0.0){
throw new PropertyVetoException(
"Invalid Comfort Temperature", evt);
}
}
- 187
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Boiler Implementierung (1/2)
Fast identisch mit dem Cooler. Arbeitet bei 100°C.
package BeansBook.Simulator;
import java.awt.*;
import java.beans.*;
// the Boiler bean class definition
public class Boiler extends TemperatureModifier
// subclasses TemperatureModifier
implements HeatingRequestListener,
// listens for heating requests
VetoableChangeListener
// vetoes property changes
{
// constructor
public Boiler() {
// a boiler is a temperature modifier that operates at
// 100 degress celsius
super(100.0, "BOILER ON", "BOILER OFF",
Color.red, Color.yellow);
}
// handle a heating request event
public void heatingRequest(ServiceRequestEvent evt) {
// set the Running property based on the value returned
// by the isStart method from the event
setRunning(evt.isStart());
}
- 188
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Boiler Implementierung (2/2)
// handle a vetoable change event
public void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException {
// only interested in ComfortTemperature
if (evt.getPropertyName().equals(
"ComfortTemperature")) {
// get the proposed temperature
Double d = (Double)evt.getNewValue();
}
}
}
// veto a temperature over 100 degrees Celsius
if (d.doubleValue() > 100.0) {
throw new PropertyVetoException(
"Invalid Comfort Temperature", evt);
}
- 189
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Klasse Thermostat
Kontrolliert die Gesamtoperation des Simulators:
• Ermöglicht, daß Benutzer Wunschtemperatur spezifiziert
• Entscheidet über An-/Abschalten der Heizung und der Kühlung
• Hat Benutzerschnittstelle
Gemäß der Spezifikationen benötigt er
• Anzeige der augenblicklichen Temperatur
• Dropdown Liste, um Einheit der Temperaturanzeige (C oder F) zu
wählen
• Anzeige der gewünschten Temperatur
• Zwischen augenblicklicher und gewünschter Temperatur kann
ebenfalls mit einer Dropdownliste hin und her geschaltet werden
• Zwei Buttons (Inkrement, Dekrement), um gewünschte Temperatur
um jeweils 1 Grad zu verändern (nur verfügbar, wenn Anzeige auf
gewünschter Temperatur steht)
Auswahl der Temperatur-Einheit
<<
Anzeige
>>
Auswahl der Temperatur Anzeige
- 190
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (1/16)
Ähnlich einer Form, in der sich mehrere andere Interface
Komponenten befinden: Nachfahre der Klasse Panel.
Einige Interfaces müssen implementiert werden:
• PropertyChangeListener: Themostat hört auf Temperature Property
des Temperature Objektes
• ActionListener: Pushbutton Ereignisse können behandelt werden.
• ItemListener: Item Ereignisse der Dropdown Listen können
behandelt werden.
package BeansBook.Simulator;
import
import
import
import
import
java.awt.*;
java.awt.event.*;
java.beans.*;
java.util.*;
java.io.*;
// the Thermostat bean class definition
public class Thermostat extends Panel // subclasses Panel
implements PropertyChangeListener, // property changes
// from temperature
// source
ActionListener,
// action events
// from buttons
ItemListener
// item events from
// choice controls
{
// the choice control for display units
protected Choice unitsChoice;
// the choice control for displaying ambient or
// comfort level temperature
protected Choice displayChoice;
- 191
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (2/16)
// button for decrementing comfort level temperature
protected Button decButton;
// button for incrementing comfort level temperature
protected Button incButton;
// label for displaying temperatures
protected Label displayLabel;
// flags for the NeedsCooling and NeedsHeating state
protected boolean bNeedsCooling = false;
protected boolean bNeedsHeating = false;
// the comfort level temperature
protected double comfortTemp = 22.0;
// the ambient temperature from the temperature source
// via property change event
// there is no direct reference to the Temperature object
protected double ambientTemp;
// flag indicating if ambient temperature is being
// displayed
protected boolean bShowingAmbient = true;
// flag indicating if Celsius units are being displayed
protected boolean bShowingCelsius = true;
// support for the constrained properties
protected VetoableChangeSupport vetoSupport;
// cooling and heating request listeners
protected transient Vector coolingListeners;
protected transient Vector heatingListeners;
- 192
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (3/16)
Constructor
public Thermostat() {
// call superclass constructor
super();
// create the support object for constrained properties
vetoSupport = new VetoableChangeSupport(this);
// use a border layout for the constituents
setLayout(new BorderLayout());
// create the
unitsChoice
displayChoice
decButton
incButton
displayLabel
constituents
= new Choice();
= new Choice();
= new Button("<<");
= new Button(">>");
= new Label("**********");
// register as action listener for the buttons
decButton.addActionListener(this);
incButton.addActionListener(this);
// register as item listener for the choice controls
displayChoice.addItemListener(this);
unitsChoice.addItemListener(this);
// disable the comfort temperature buttons
decButton.setEnabled(false);
incButton.setEnabled(false);
// add the constituents in their appropriate locations
add(unitsChoice, BorderLayout.NORTH);
add(displayChoice, BorderLayout.SOUTH);
add(decButton, BorderLayout.WEST);
add(incButton, BorderLayout.EAST);
add(displayLabel, BorderLayout.CENTER);
// use center alignment for the temperature display
displayLabel.setAlignment(Label.CENTER);
- 193
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (4/16)
// add the units to the choice control
unitsChoice.add("Celsius");
unitsChoice.add("Fahrenheit");
}
// add the display types to the choice control
displayChoice.add("Ambient");
displayChoice.add("Comfort");
actionPerformed
// handle an action event
public void actionPerformed(ActionEvent evt) {
// change in temperature
double tempDelta;
// delta value for rounding
double roundingDelta;
// it was the decrement button
if (evt.getSource() == decButton) {
// reduce temp by 1
tempDelta = -1.0;
// delta is 0 for rounding down
roundingDelta = 0.0;
}
else
{
// it was the increment button
// increase temp by 1
tempDelta = 1.0;
}
// delta is 1 for rounding up
roundingDelta = 1.0;
- 194
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (5/16)
// the new proposed comfort temperature
double newValue;
// displaying temperatures in Celsius
if (bShowingCelsius) {
// just add the delta
newValue = comfortTemp + tempDelta;
}
else {
// displaying in Fahrenheit
// convert to Fahrenheit, add the delta,
// and convert back
double t = 32.0 + ((comfortTemp * 9.0) / 5.0);
t += tempDelta;
newValue = (t - 32.0) * 5.0 / 9.0;
}
// the old value object for firing the vetoable
// change event
Double old = new Double(comfortTemp);
try {
// fire the event
vetoSupport.fireVetoableChange("ComfortTemperature",
old,
new Double(newValue));
// if we get this far we can make the change
synchronized (this) {
comfortTemp = newValue;
}
}
catch (PropertyVetoException e) {
// the change was vetoed by a listening object, but
// if we have a fractional part, we could try
// rounding the value to use a whole number
double wholePart = (double)old.longValue();
if ((old.doubleValue() - wholePart) == 0.0) {
// we can't make a change
return;
}
- 195
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (6/16)
// attempt to alter the comfort temperature using the
// whole part of the old value and the rounding delta
newValue = wholePart + roundingDelta;
try {
// fire the event
vetoSupport.fireVetoableChange(
"ComfortTemperature",
old,
new Double(newValue));
}
catch (PropertyVetoException ee) {
// we couldn’t make this change either
return;
}
}
// we can go ahead and change it now
synchronized (this) {
comfortTemp = wholePart + roundingDelta;
}
// set the needs cooling and needs heating states,
// comparing the ambient and comfort level temperatures
setNeedsCooling((ambientTemp > comfortTemp) &&
((ambientTemp - comfortTemp) >= 1.0));
setNeedsHeating((ambientTemp < comfortTemp) &&
((comfortTemp - ambientTemp) >= 1.0));
}
// redisplay the temperature
displayTemp();
- 196
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (7/16)
displayTemp
// display the temperature
protected void displayTemp() {
// temporary temperature value
double t;
if (bShowingAmbient) {
// use the ambient temperature
t = ambientTemp;
}
else {
// use the comfort level temperature
t = comfortTemp;
}
// if not using Celsius, convert to Fahrenheit
if (!bShowingCelsius) {
t = 32.0 + ((t * 9.0) / 5.0);
}
}
// display whole number part of the temperature
Double d = new Double(t);
displayLabel.setText(new Long(
d.longValue()).toString());
- 197
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (8/16)
itemStateChanged
// handle item state change events
public void itemStateChanged(ItemEvent evt) {
if (evt.getSource() == displayChoice &&
evt.getStateChange() == ItemEvent.SELECTED) {
// determine the newly selected item string
String sel = (String)evt.getItem();
if (sel.equals("Comfort")) {
// showing comfort level, not ambient
bShowingAmbient = false;
// enable comfort level buttons
decButton.setEnabled(true);
incButton.setEnabled(true);
// display the temperature
displayTemp();
}
else if (sel.equals("Ambient")) {
// showing ambient temperature
bShowingAmbient = true;
// disable the comfort level buttons
decButton.setEnabled(false);
incButton.setEnabled(false);
// display the temperature
displayTemp();
}
}
- 198
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (9/16)
else if (evt.getSource() == unitsChoice &&
evt.getStateChange() == ItemEvent.SELECTED) {
// a new temperature units item has been selected
Choice pp = (Choice)evt.getSource();
// determine the newly selected item string
String sel = (String)evt.getItem();
if (sel.equals("Celsius")) {
// showing Celsius
bShowingCelsius = true;
// display the temperature
displayTemp();
}
else if (sel.equals("Fahrenheit")) {
// showing Fahrenheit, not Celsius
bShowingCelsius = false;
}
}
}
// display the temperature
displayTemp();
add/removeHeatingRequestListener
// add a heating request listener
public synchronized void
addHeatingRequestListener(HeatingRequestListener l) {
// add a listener if it is not already registered
if (heatingListeners == null) {
heatingListeners = new Vector();
}
}
if (!heatingListeners.contains(l)) {
heatingListeners.addElement(l);
}
- 199
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (10/16)
// remove the heating request listener
public synchronized void
removeHeatingRequestListener(HeatingRequestListener l) {
// remove it if it is registered
if (heatingListeners != null) {
heatingListeners.removeElement(l);
}
}
add/removeCoolingRequestListener
// add a cooling request listener
public synchronized void
addCoolingRequestListener(CoolingRequestListener l) {
// add a listener if it is not already registered
if (coolingListeners == null) {
coolingListeners = new Vector();
}
}
if (!coolingListeners.contains(l)) {
coolingListeners.addElement(l);
}
// remove the cooling request listener
public synchronized void
removeCoolingRequestListener(CoolingRequestListener l) {
// remove it if it is registered
if (coolingListeners != null) {
coolingListeners.removeElement(l);
}
}
getComfortTemperature
// return the comfort temperature
public synchronized double getComfortTemperature() {
return comfortTemp;
}
- 200
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (11/16)
setNeedsCooling
// set the needs cooling state
private void setNeedsCooling(boolean b) {
// do nothing if there is no change
if (b == bNeedsCooling) {
return;
}
bNeedsCooling = b;
// nothing else to do if collection isn’t allocated yet
if (coolingListeners == null) {
return;
}
// fire the cooling service request
ServiceRequestEvent evt = new ServiceRequestEvent(
this, bNeedsCooling);
// make a copy of the listener object vector so that it
// cannot be changed while we are firing events
Vector v;
synchronized(this) {
v = (Vector) coolingListeners.clone();
}
}
// fire the event to all listeners
int cnt = v.size();
for (int i = 0; i < cnt; i++) {
CoolingRequestListener client =
(CoolingRequestListener)v.elementAt(i);
client.coolingRequest(evt);
}
- 201
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (12/16)
setNeedsHeating
// set the needs heating state
private void setNeedsHeating(boolean b) {
// do nothing if there is no change
if (b == bNeedsHeating) {
return;
}
bNeedsHeating = b;
// nothing else to do if collection isn’t allocated yet
if (heatingListeners == null) {
return;
}
// fire the heating service request
ServiceRequestEvent evt =
new ServiceRequestEvent(this, bNeedsHeating);
// make a copy of the listener object vector so that it
// cannot be changed while we are firing events
Vector v;
synchronized(this) {
v = (Vector) heatingListeners.clone();
}
}
// fire the event to all listeners
int cnt = v.size();
for (int i = 0; i < cnt; i++) {
HeatingRequestListener client =
(HeatingRequestListener)v.elementAt(i);
client.heatingRequest(evt);
}
- 202
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (13/16)
add/removeVetoableChangeListene
r
// add vetoable change listener
public void
addVetoableChangeListener(VetoableChangeListener l) {
vetoSupport.addVetoableChangeListener(l);
}
// remove vetoable change listener
public void
removeVetoableChangeListener(VetoableChangeListener l) {
vetoSupport.removeVetoableChangeListener(l);
}
propertyChange
// handle a property change from another source
public void propertyChange(PropertyChangeEvent evt) {
// check for a Temperature property change
if (evt.getPropertyName().equals("Temperature")) {
// modify the ambient temperature
Double d = (Double)evt.getNewValue();
ambientTemp = d.doubleValue();
// update the bNeedsCooling and bNeedsHeating
// variables
setNeedsCooling((ambientTemp > comfortTemp) &&
((ambientTemp - comfortTemp) >= 1.0));
setNeedsHeating((ambientTemp < comfortTemp) &&
((comfortTemp - ambientTemp) >= 1.0));
}
// display the temperature
displayTemp();
}
- 203
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (14/16)
writeObject
private void writeObject(ObjectOutputStream stream)
throws java.io.IOException {
// perform default writing first
stream.defaultWriteObject();
// if we have allocated coolingListeners
if (coolingListeners != null) {
// clone the vector in case one is added or removed
Vector v = null;
synchronized (this) {
v = (Vector) coolingListeners.clone();
}
int cnt = v.size();
for(int i = 0; i < cnt; i++) {
// get the listener element from the collection
CoolingRequestListener l =
(CoolingRequestListener)v.elementAt(i);
}
}
// if the listener is serializable,
// write it to the stream
if (l instanceof Serializable) {
stream.writeObject(l);
}
// a null object marks the end of the
// cooling request listeners
stream.writeObject(null);
- 204
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (15/16)
// if we have allocated heatingListeners
if (heatingListeners != null) {
// clone the vector in case one is added or removed
Vector v = null;
synchronized (this) {
v = (Vector) heatingListeners.clone();
}
int cnt = v.size();
for(int i = 0; i < cnt; i++) {
// get the listener element from the collection
HeatingRequestListener l =
(HeatingRequestListener)v.elementAt(i);
}
}
}
// if the listener is serializable,
// write it to the stream
if (l instanceof Serializable) {
stream.writeObject(l);
}
// a null object marks the end of the heating
// request listeners
stream.writeObject(null);
- 205
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.2
Der vollständige Temperaturregelungs-Simulator
Implementierung des Simulators
Thermostat Implementierung (16/16)
readObject
// handle the reading of the object state
private void readObject(ObjectInputStream stream)
throws java.io.IOException {
try {
stream.defaultReadObject();
Object l;
// get the cooling request listeners
while(null != (l = stream.readObject())) {
addCoolingRequestListener(
(CoolingRequestListener)l);
}
// get the heating request listeners
while(null != (l = stream.readObject())) {
addHeatingRequestListener(
(HeatingRequestListener)l);
}
}
}
catch (ClassNotFoundException e) {
throw new IOException();
}
}
- 206
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.3
Der vollständige Temperaturregelungs-Simulator
Der Simulator als Applet
Der Simulator als Applet (1/2)
Ein Applet, das die bisher entwickelten Beans verwendet.
• Das Applet erzeugt Instanzen von Temperature, Thermostat, Boiler
und Cooler und
• erzeugt die notwendigen Verbindungen.
All dies geschieht in der init() Methode.
import
import
import
import
java.applet.*;
java.awt.*;
BeansBook.Simulator.*;
java.beans.*;
// the SimulatorSample applet class
public class SimulatorSample extends Applet {
// the applet init method
public void init() {
// use a flow layout, with components centered, and
// a 20 pixel separation between components
setLayout(new FlowLayout(FlowLayout.CENTER, 20, 20));
// create a temperature
Temperature t = new Temperature();
// create a thermostat
Thermostat th = new Thermostat();
// create a cooler
Cooler c = new Cooler();
// create a boiler
Boiler b = new Boiler();
// add the thermostat, cooler, and boiler to the applet
add(th);
add(c);
add(b);
- 207
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.3
Der vollständige Temperaturregelungs-Simulator
Der Simulator als Applet
Der Simulator als Applet (2/2)
// make the thermostat a property change listener of the
// temperature object
t.addPropertyChangeListener(th);
// make the cooler a cooling request listener of the
// thermostat object
th.addCoolingRequestListener(c);
// make the boiler a heating request listener of the
// thermostat object
th.addHeatingRequestListener(b);
// make the boiler and cooler vetoable change listeners
// of the thermostat object
th.addVetoableChangeListener(b);
th.addVetoableChangeListener(c);
try {
// make the temperature object a temperature pulse
// listener of the cooler and boiler objects
c.addTemperaturePulseListener(t);
b.addTemperaturePulseListener(t);
}
catch (java.util.TooManyListenersException e) { }
// start the temperature object at 0 degrees
t.setTemperature(0);
}
}
- 208
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.3
Der vollständige Temperaturregelungs-Simulator
Speichern in einer JAR Datei
Speichern in einer JAR Datei (1/2)
Damit können alle Bestandteile gemeinsam weitergegeben werden und
sie können auch in der BeanBox verwendet werden.
Manifest-Datei
Manifest-Version: 1.0
Name: BeansBook/Simulator/Boiler.class
Java-Bean: True
Name: BeansBook/Simulator/Cooler.class
Java-Bean: True
Name: BeansBook/Simulator/CoolingRequestListener.class
Java-Bean: False
Name: BeansBook/Simulator/HaetingRequestListener.class
Java-Bean: False
Name: BeansBook/Simulator/ServiceRequestEvent.class
Java-Bean: False
Name: BeansBook/Simulator/Temperature.class
Java-Bean: True
Name: BeansBook/Simulator/TemperatureModifier.class
Java-Bean: False
Name: BeansBook/Simulator/TemperaturePulseEvent.class
Java-Bean: False
Name: BeansBook/Simulator/TemperaturePulseListener.class
Java-Bean: False
Name: BeansBook/Simulator/Thermostat.class
Java-Bean: True
- 209
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
8.
8.3
Der vollständige Temperaturregelungs-Simulator
Speichern in einer JAR Datei
Speichern in einer JAR Datei (1/2)
Die Datei Simulator.mft und die Class-Datei des Applets
SimulatorSample.class müssen sich in einem Verzeichnis oberhalb
BeansBook befinden.
Die JAR Datei wird erzeugt:
jar cvfm Simulator.jar Simulator.mft
BeansBook/Simulator/*.class
In der BeanBox
Damit kann der Simulator nun auch in der BeanBox benutzt werden.
- 210
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
Introspection
Der Java Reflection Mechanismus kann Informationen über
• Properties,
• Methoden und
• behandelte Ereignisse
der Beans sammeln, in dem der Programmierer sich an bestimmte
Namenskonventionen (sog. design patterns) hält.
Eventuell reicht aber diese Information nicht aus oder man möchte
nicht alle so verfügbaren Informationen veröffentlichen.
Oder man möchte sich nicht an die Namenskonventionen halten
müssen.
Manchmal sind Informationen auch nicht durch Namenskonventionen
darstellbar (z.B. ein graphische Icon für eine Bean).
Der Mechanismus, Informationen über eine Bean explizit zur
Verfügung zu stellen, heißt Introspection.
Dafür wird eine Klasse erzeugt, die speziell zur Beschreibung der Bean
dient.
- 211
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
9.1
Introspection
Das BeanInfo Interface
Das BeanInfo Interface (1/2)
Diese Klasse muß das java.beans.BeanInfo Interface implementieren.
Dessen Methoden:
Methode
getAdditionalBeanInfo()
getBeanDescriptor()
getDefaultEventIndex()
getDefaultPropertyIndex()
getEventSetDescriptors()
getIcon()
getMethodDescriptors()
getPropertyDescriptors()
Beschreibung
Gibt zusätzliche BeanInfo Objekte
zurück, die für diese Bean relevant
sind
Gibt das Bean Descriptor Objekt
Gibt den Default Event Index
Gibt den Default Property Index
Gibt die Event Set Deskriptoren
Gibt den zu der Bean gehörigen Icon
Gibt die Method Deskriptoren
Gibt die Property Deskriptoren
Reflection: Dieser Mechanismus anlysiert die Bean, um Properties,
Methoden und Ereignisse herauszufinden.
Introspection: Ein Meta-Objekt stellt die Informationen zur Verfügung.
Vorteil der Introspection:
• Metainformation muß zur Laufzeit nicht mitgetragen werden.
• Run-Time Version ist nicht zur Entwicklung einsetzbar.
Die BeanInfo Klasse hat ihre eigenen Namenskonventionen:
Ihr Name ist der Klassenname der Bean mit „BeanInfo“ angehängt.
Also z.B.
Xyz
und
XyzBeanInfo
- 212
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
9.1
Introspection
Das BeanInfo Interface
Das BeanInfo Interface (2/2)
Normalerweise wird die BeanInfo Klasse in demselben Package wie
das der Bean gesucht.
Man kann jedoch noch einen BeanInfo SearchPath angeben:
getBeanInfoSearchPath()
setBeanInfoSearchPath()
der Klasse
java.beans.Introspector
Nachteil: Zwei unabhängige Klassen müssen konsistent gehalten
werden.
Jede der Methoden des BeanInfo Interfaces kann null zurückgeben:
• Bedeutet: Es gibt diese Information nicht: Verwende Reflection.
Klasse java.beans.SimpleBeanInfo.
• Liefert immer null zurück
• Man kann dann einen Nachfahren dieser Klasse definieren, der die
gewünschten Methoden überschreibt.
- 213
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
9.1
Introspection
Das BeanInfo Interface
BeanInfo und Superklassen
• Bei Reflection werden auch die Superklassen analysiert.
• Dabei hat die einmal bei einer der Subklassen gefundene
Information Vorrang vor später bei einer Superklasse gefundenen
Informationen.
• Bei Introspection wird die durch die BeanInfo Klasse über ein
bestimmtes Feature zur Verfügung gestellte Information nicht mehr
bei Vorfahrenklassen gesucht.
• Informiert BeanInfo z.B. über Events, so müssen alle Events
beschrieben werden, auch die, die die Superklassen verwenden.
• Es gibt die Möglichkeit, von einem BeanInfo Objekt auf die BeanInfo
Objekte der Superklassen zu verweisen.
- 214
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.1 Feature Descriptor
Feature Descriptor
• Alle Aspekte einer Bean, die durch Introspection beschrieben
werden können, können als Features der Bean angesehen werden.
• Diese haben gemeinsame Eigenschaften, die durch die Klasse
java.beans.FeatureDescriptor beschrieben werden.
Methoden des Features Bedeutung
setName()
Name
getName()
setDisplayName()
getDisplayName()
setShortDescription()
getShortDescription()
setExpert()
isExpert()
setHidden()
isHidden()
setValue()
getValue()
attributeNames()
„Freundlicherer“ Name, z.B. für Anzeigen
Beschreibung
Feature nur für Experten Modus
Wenn true: Zeige dies Feature nur im
Entwicklungswerkzeug
Zugriff auf assoziatives Array mit
Schlüsseln (Keys) und Werten
Liefere eine Enumeration, um durch alle
Keys zu iterieren
- 215
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.2 Bean Descriptor
Bean Descriptor
java.beans.BeanDescriptor beschreibt die Klassen, die die Bean und
den Bean Customizer implementieren.
Konstruktoren der Klasse:
public BeanDescriptor(Class beanClass)
public BeanDescriptor(Class beanClass,
Class customizerClass)
• Parameter der ersten Version:
Klasse, die die zugehörige Bean implementiert.
• Zusätzlicher Parameter der zweiten Version:
Klasse, die den Customizer der zugehörigen Bean implementiert.
Für unser Thermostat Objekt würde die Erzeugung der BeanDescriptor
Instanz wie folgt aussehen:
BeanDescriptor bd = new
BeanDescriptor(BeansBook.Simulator.Thermostat.class);
Benutzer des BeanDescriptor Objektes würden die Methoden
• getBeanClass() oder
• getCustomizerClass()
verwenden, um Referenzen auf die entsprechenden Klassen zu
erhalten.
- 216
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.2 Bean Descriptor
Bean Descriptor
Beispiel
Definition einer BeanInfo Klasse für die Thermostat Klasse:
package BeansBook.Simulator;
import java.beans.*;
public class ThermostatBeanInfo extends SimpleBeanInfo {
// return the bean descriptor
public BeanDescriptor getBeanDescriptor() {
// create the bean descriptor
BeanDescriptor bd = new
BeanDescriptor(Thermostat.class);
// set the display name
bd.setDisplayName("Simulated Thermostat");
}
}
// return the object
return bd;
- 217
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.3 Icons
Icons (1/2)
Jede Bean kann einen zugehörigen Icon besitzen, z.B. um im
Entwicklungstool in einer Beans-Palette darzustellen.
Randbedingungen:
• GIF Format
• 16 x 16 oder 32 x 32 Pixels
• Farbe oder monochrom
Nehmen wir an, wir haben einen 16 x 16 farbigen GIF Icon:
thermostat.gif.
• Diese Datei befindet sich im selben Verzeichnis wie die zugehörige
Klasse (muß nicht sein, ist aber praktisch).
Damit der Introspector dieses Feature finden kann, implementieren
wir die Methode getIcon().
Sie wird mit einem Parameter aufgerufen, der angibt, welche der vier
möglichen Varianten gesucht wird.
- 218
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.3 Icons
Icons (1/2)
Fortsetzung der obigen Klassendefinition:
// get an icon
public java.awt.Image getIcon(int iconKind) {
// we're only supporting 16x16 color icon
if (iconKind == BeanInfo.ICON_COLOR_16x16) {
// load the thermostat.gif file
java.awt.Image img = loadImage("thermostat.gif");
}
}
// return the image
return img;
// return null for all other icon formats
return null;
loadImage() wird von SimpleBeanInfo zur Verfügung gestellt.
Mögliche BeanInfo Konstanten:
ICON_COLOR_16x16
ICON_COLOR_32x32
ICON_MONO_16x16
ICON_Monoi_32x32
Ergänzung von Simulator.mft:
Name: BeansBook/Simulator/ThermostatBeanInfo.class
Java-Bean: False
Name: BeansBook/Simulator/thermostat.gif
Java-Bean: False
Erzeugung der JAR Datei:
jar cvfm Simulator.jar Simulator.mft
BeansBook/Simulator/*.class BeansBook/Simulator/*.gif
In BeanBox: Zusätzlich der Icon und als Display Name „Simulated
Thermostat“.
Alle sonstigen Informationen wie zuvor über Reflection.
- 219
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.4 Property Descriptors
Property Descriptors
• Explizite Informationen über Properties.
• Basis ist die Klasse java.beans.PropertyDescriptor.
• Drei verschiedene Konstruktoren für drei Varianten.
Standard Namenskonvention
Eigenschaft hat get-/set-Methoden entsprechend den StandardNamenskonventionen.
public PropertyDescriptor(String propertyName,
Class beanClass)
throws IntrospectionException;
1. Parameter: Name der Property
2. Parameter: Klasse, die die Bean implementiert
Exception passiert, wenn Property nicht so implementiert ist.
- 220
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.4 Property Descriptors
Property Descriptors:
Standard Namenskonventionen
Beispiel für Klasse Temperature (1/2)
package BeansBook.Simulator;
import java.beans.*;
import java.lang.reflect.*;
public class TemperatureBeanInfo extends SimpleBeanInfo {
// return a bean descriptor for the Temperature object
public BeanDescriptor getBeanDescriptor() {
// create an instance of BeanDescriptor
BeanDescriptor bd = new
BeanDescriptor(Temperature.class);
bd.setDisplayName("Temperature Source");
return bd;
}
- 221
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.4 Property Descriptors
Property Descriptors:
Standard Namenskonventionen
Beispiel für Klasse Temperature (2/2)
// return the property descriptors
public PropertyDescriptor[] getPropertyDescriptors() {
try {
// create a property descriptor for the
// Temperature property
PropertyDescriptor pd = new
PropertyDescriptor("Temperature",
Temperature.class);
// the Temperature property is bound
pd.setBound(true);
// the Temperature property is not constrained
pd.setConstrained(false); // is default
// create the property descriptor array and return it
PropertyDescriptor[] pda = { pd };
return pda;
}
}
}
catch (IntrospectionException e) {
return null;
}
Die Klasse zeigt hier an, daß sie propertyChange Events feuert, aber
keine vetoableChange Events.
- 222
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.4 Property Descriptors
Property Descriptors:
Nichtstandard Methodennamen
Der Konstruktor:
public PropertyDescriptor(String propertyName,
Class beanClass;
String getterName,
String setterName)
throws IntrospectionException;
Für den Methodennamen kann auch null angegeben werden (z.B. bei
read-only Zugriff).
Hier ist man nun frei in der Namenswahl der Zugriffsmethoden.
Obiges Beispiel im Ausschnitt
public PropertyDescriptor[] getPropertyDescriptors() {
try {
PropertyDescriptor pd = new
PropertyDescriptor("Temperature",
Temperature.class,
"returnTemperature",
"assignTemperature);
pd.setBound(true);
pd.setConstrained(false); // is default
PropertyDescriptor[] pda = { pd };
return pda;
}
}
catch (IntrospectionException e) {
return null;
}
- 223
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.4 Property Descriptors
Property Descriptors:
Nichtstandard Methoden-Objekte
Anstelle von
• Namen als Strings werden
• Objekte der Klasse java.lang.reflect.Method
übergeben.
Dabei muß nicht mehr die Implementierungsklasse übergeben
werden, da diese in den Methoden-Objekten enthalten ist:
public PropertyDescriptor(String
Method
Method
throws
- 224
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
propertyName,
getter,
setter)
IntrospectionException;
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.4 Property Descriptors
Property Descriptors:
Nichtstandard Methoden-Objekte
Obiges Beispiel neu (1/2)
public PropertyDescriptor[] getPropertyDescriptors()
try {
// get the Temperature class
Class c = Temperature.class;
{
// get the get method for the Temperature property
Method getter = c.getMethod("returnTemperature",
null);
// create the parameters array for the set method
// of the Temperature property type double
Class[] params = { java.lang.Double.TYPE };
// get the set method
Method setter = c.getMethod("assignTemperature",
params);
PropertyDescriptor pd = new
PropertyDescriptor("Temperature",
getter,
setter);
pd.setBound(true);
pd.setConstrained(false); // is default
PropertyDescriptor[] pda = { pd };
return pda;
}
- 225
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.4 Property Descriptors
Property Descriptors:
Nichtstandard Methoden-Objekte
Obiges Beispiel neu (2/2)
}
catch (IntrospectionException e) {
return null;
}
catch (NoSuchMethodException e) {
return null;
}
catch (SecurityException e) {
return null;
}
Die Klasse java.beans.PropertyDescriptor stellt Methoden zur
Verfügung, die es erlauben,
• die get- und set-Methoden einer bestimmten Property,
• ihren Datentyp und,
• ob sie bound oder constrained ist,
zu erhalten.
- 226
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.5 Default Property
Default Property
Kann in einigen Entwicklungsumgebungen von Interesse sein.
• Zuweisen eines Wertes an den Namen der Bean, ohne eine Property
anzugeben.
• Dann erhält die Default Property diesen Wert.
Implementierung durch die Methode getDefaultPropertyIndex().
Beispiel
public PropertyDescriptor[] getPropertyDescriptors() {
try {
PropertyDescriptor color = new PropertyDescriptor(
"Color",
Example.class);
PropertyDescriptor color = new PropertyDescriptor(
"Font",
Example.class);
PropertyDescriptor color = new PropertyDescriptor(
"Size",
Example.class);
PropertyDescriptor[] pda = { colr, font, size };
return pda;
}
}
catch (IntrospectionException e) {
return null
}
public int getDefaultPropertyIndex() {
// font is the default
return 1;
}
- 227
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.6 Deskriptoren für Indizierte Properties
Deskriptoren für Indizierte Properties
Beschrieben durch Instanz von
java.beans.IndexedPropertyDescriptor,
ein Nachfahre von java.beans.PropertyDescriptor.
Indizierte Properties haben Methoden, um auf eine bestimmte oder
auf alle Properties zuzugreifen.
Erste Konstruktorvariante
Falls die Standard Namenskonventionen für normale und indizierte
Properties eingehalten wurden:
public IndexedPropertyDescriptor(String propertyName,
Class beanClass)
throws IntrospectionException;
Als Beispiel nehmen wir unsere Klasse WatchList.
Da sie strikt nach den Namenskonventionen erstellt wurde, können
wir die folgende Implementierung verwenden:
public PropertyDescriptor[] getPropertyDescriptors() {
try {
IndexedPropertyDescriptor ip =
new IndexedPropertyDescriptor("Stocks",
WatchList.class);
PropertyDescriptor[] pda = { ip };
retrun pda;
}
catch (IntrospectionException) {
return null;
}
}
- 228
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.6 Deskriptoren für Indizierte Properties
Deskriptoren für Indizierte Properties
Weitere Konstruktorvarianten
Die anderen Varianten sind analog wie bei den nicht-indizierten
Properties:
public IndexedPropertyDescriptor(String propertyName,
Class beanClass,
String getterName,
String setterName,
String indexedGetterName,
String indexedSetterName)
throws IntrospectionException;
und
public IndexedPropertyDescriptor(String propertyName,
Method getter,
Method setter,
Method indexedGetter,
Method indexedSetter)
throws IntrospectionException;
- 229
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.7 Methoden Deskriptoren
Methoden Deskriptoren
• Normalerweise werden Methoden durch den Zusatz public
veröffentlicht.
• Mit Hilfe dieser Deskriptoren können die für einzelne Beans zur
Verfügung stehenden Methoden explizit genannt werden.
• Weiterhin können besser beschreibende Informationen zu den
Methoden gegeben werden.
Methoden werden veröffentlicht,
• indem Instanzen von java.beans.MethodDescriptor erzeugt werden
und
• diese in einem Array durch die Methode getMethodDescriptors() der
BeanInfo Klasse geliefert werden.
Variante 1
Eine Methode als Parameter:
public MethodDescriptor(Method method);
- 230
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.7 Methoden Deskriptoren
Methoden Deskriptoren
Variante 2
Für die Parameter der Methode, die in der Instanz von Method formal
beschrieben sind, können beschreibende Informationen hinzugefügt
werden.
Dazu wird eine Instanz der Klasse java.beans.ParameterDescriptor
verwendet.
Diese Klasse ist Nachfahre von java.beans.FeatureDescriptor. Sie fügt
keine weitere Informationen zur dieser Klasse hinzu.
Konstruktor:
public MethodDescriptor(Method method,
ParameterDescriptor parameterDescriptors[]);
Parameterdeskriptoren als Array.
• Für jeden Parameter der Methode muß eine Beschreibung
angegeben werden.
Beispiel WatchList
Um das zu veranschaulichen fügen wir unserer WatchList zwei
Methoden hinzu:
public synchronized void clearStocks();
public synchronized boolean sortStocks(int nOrder);
- 231
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.7 Methoden Deskriptoren
Methoden Deskriptoren
getMethodDescriptors
public MethodDescriptor[] getMethodDescriptors() {
try {
Class c = WatchList.class;
// method clearStocks
Method clear = c.getMethod("clearStocks", null);
MethodDescriptor clearDesc = new
MethodDescriptor(clear);
clearDesc.setShortDescription(
"Clears the list of stocks");
// method sortStocks
Class[] params = { java.lang.Integer.TYPE };
Method sort = c.getMethod("sortStocks", params);
ParameterDescriptor pd = new ParameterDescriptor();
pd.setShortDescription("Specifies the sort order");
// array of descriptors for parameters
ParameterDescriptor[] s = { pd };
MethodDescriptor sortDesc = new
MethodDescriptor(sort, s);
sortDesc.setShortDescription(
"Sorts the list of stocks");
// construct method descriptor array
MethodDescriptor[] mda = { clearDesc, sortDesc };
return mda;
}
}
catch (SecurityException e) {
return null;
}
catch (NoSuchMethodException e) {
return null;
}
- 232
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.7 Methoden Deskriptoren
Methoden Deskriptoren
Auswirkungen
• Nur die hier aufgeführten Methoden der Klasse WatchList sind für
Entwicklungswerkzeuge sichtbar.
• Hierdurch wurden auch die Methoden von Vorfahrenklassen
unsichtbar. (Wir werden einen Weg kennenlernen, um das zu
beheben).
• Unabhängig hiervon sind jedoch Zugriffsmethoden für Properties
und Registrierungsmethoden für Ereignisse. Sie gehören zu anderen
Features.
• Auch durch Programmierung kann man unabhängig davon auf alle
öffentlichen Methoden zugreifen.
- 233
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.8 Event Set Deskriptoren
Event Set Deskriptoren
• Veröffentlichen die Ereignisse, die eine Bean feuern kann.
• Alle Ereignisse, die über dasselbe Listener Interface empfangen
werden, werden in einem solchen Set zusammengefaßt.
• Dieser ist eine Instanz der Klasse java.beans.EventSetDescriptor.
• Die BeanInfo Klasse muß die Methode getEventSetDescriptors()
implementieren, die ein Array von Event Set Deskriptoren
zurückgibt.
Auch hier kann der Konstruktor unterschiedliche Formen annehmen.
Erste Konstruktorvariante
Erwartet
• die Standard Namenskonventionen für die Registrierung und
Deregistrierung von Listeners sowie
• ein Ereignisobjekt mit nur einem Parameter, der auch den
Namenskonventionen entspricht.
public EventSetDescriptor(Class sourceClass,
String eventSetName,
Class listenerType,
String listenerMethodName)
throws IntrospectionException;
- 234
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.8 Event Set Deskriptoren
Event Set Deskriptoren
Erste Konstruktorvariante
Anwendbar, wenn
• ein SampleListener Interface
• eine einzige Methode mit einem einzigen Parameter vom Typ SampleEvent hat,
und wenn
• die Klasse, die die Bean implementiert, die Methoden addSampleListener() und removeSampleListener() zur Verfügung stellt.
Betrachten wir als Beispiel wieder die Klasse TemperatureBeanInfo.
• Das Temperature Objekt kann ein Property Change Event feuern.
• Dafür können wir die Methode getEventSetDescriptors()
implementieren:
// return the event set descriptors
public EventSetDescriptor[] getEventSetDescriptors() {
try {
// create the event set descriptor
EventSetDescriptor ed = new
EventSetDescriptor(Temperature.class,
"Property Change Event",
PropertyChangeListener.class,
"propertyChange");
// create the descriptor array and return it
EventSetDescriptor[] eda = { ed } ;
return eda;
}
}
catch (IntrospectionException e) {
return null;
}
- 235
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.8 Event Set Deskriptoren
Event Set Deskriptoren
Zweite Konstruktorvariante
Ermöglicht mehr Flexibilität in Namen und Anzahl der Methoden in
dem Listener Inteface.
public EventSetDescriptor(Class sourceClass,
String eventSetName,
Class listenerType,
String listenerMethodNames[],
String addListenerMethodName,
String removeListenerMethodName)
throws IntrospectionException;
Diese Version unseres Beispiels:
public EventSetDescriptor[] getEventSetDescriptors() {
try {
String[] names = { "propertyChange" };
EventSetDescriptor ed = new
EventSetDescriptor(Temperature.class,
"Property Change Event",
PropertyChangeListener.class,
names,
"addPropertyChangeListener",
"removePropertyChangeListener");
EventSetDescriptor[] eda = { ed } ;
return eda;
}
}
catch (IntrospectionException e) {
return null;
}
• Eventlistener Registriermethoden können beliebige Namen haben.
• EventListener Interface kann mehrere Methoden enthalten.
• Jedoch nur ein Parameter nach Namenskonvention.
- 236
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.8 Event Set Deskriptoren
Event Set Deskriptoren
Weitere Konstruktorvarianten
Es gibt noch zwei weitere Varianten:
public EventSetDescriptor(String eventSetName,
Class listenerType,
Method listenerMethods[],
Method addListenerMethod,
Method removeListenerMethod)
throws IntrospectionException;
und
public EventSetDescriptor(String eventSetName,
Class listenerType,
MethodDescriptor listenerMethodDescriptors[],
Method addListenerMethod,
Method removeListenerMethod)
throws IntrospectionException;
Die EventSetDescriptor Klasse stellt Methoden zur Verfügung,
• um die Listener Methoden als Instanzen von
java.lang.reflect.Method oder java.beans.MethodDescriptor zu
liefern und
• via setUnicast() und isUnicast() unicast Ereignisse zu
unterstützen.
- 237
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.1
Das BeanInfo Interface
9.1.9 Default Event Set
Default Event Set
Wie bei den Properties kann es wünschenswert sein, einen Event Set
als Default zu spezifizieren.
• Dazu muß man die Methode getDefaultEventIndex()
implementieren.
- Die Klasse SimpleBeanInfo liefert mit dieser Methode eine –1 zurück, was bedeutet, daß es keinen Default Event Set gibt.
• Der Nutzen dieser Möglichkeit ist nicht sehr einleuchtend.
- 238
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
9.2
Introspection
Zusätzliche BeanInfo Objekte
Zusätzliche BeanInfo Objekte
Informationen der Vorfahrenklassen fehlen , wenn explizite
Informationen durch eine Subklasse zur Verfügung gestellt werden.
• Klasse AA veröffentlicht die Property propA.
• Klasse BB sei Nachfahre von AA und veröffentliche seine eigene
Property propB.
- Mit low-level Reflection sehen wir bei BB die beiden Properties
propA und propB.
• Sobald jedoch für BB eine eigene BeanInfo Klasse BBBeanInfo erzeugt
wird,
- die die Methode getPropertyDescriptor() implementiert,
- welche ihrerseits ein Property Descriptor Array mit nur einem
Element, nämlich propB liefert,
sieht man nicht mehr die geerbte Property propA.
Das java.beans.BeanInfo Interface enthält eine Methode
getAdditionalBeanInfo(), mit deren Hilfe man weitere BeanInfo
Objekte erhalten kann, die für diese Klasse relevant sind.
Original-BeanInfo Instanz hat Vorrang vor den zusätzlichen.
Bei den zusätzlichen: Später im Array stehende Vorrang vor früheren
(Vererbungshierarchie). BeanInfo für Wurzelklasse bei Index 0.
Klasse AA
Klasse BB
0
BeanInfo für
Klasse AA
1
BeanInfo für
Klasse BB
getAdditionalBeanInfo()
Klasse CC
Klasse CCBeanInfo
- 239
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.2
Zusätzliche BeanInfo Objekte
9.2.1 Introspector
Introspector
Um solche zusätzlichen BeanInfo-Klassen zu finden, kann die Klasse
java.beans.Introspector benutzt werden.
• Falls keine entsprechende BeanInfo Klasse vorhanden ist, verwendet
Introspector den normalen Reflection Mechanismus.
Beispiel einer getAdditionalBeanInfo() Methode der Klasse BBBeanInfo:
public BeanInfo[] getAdditionalBeanInfo() {
try {
BeanInfo[] bia = { Introspector.getBeanInfo(AA.class) };
return bia;
}
catch (IntrospectionException e) {
return null;
}
}
- 240
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
Introspection
9.2
Zusätzliche BeanInfo Objekte
9.2.1 Introspector
Introspector
Mit Hilfe von java.beans.Introspector kann man z.B. ein ReportingTool von Beans schreiben. In BeanBox schon integriert.
Ergebnis (so ähnlich):
CLASS: BeansBook.Simulator.Temperature
H => Hidden
E => Expert
[ => Indexed Property
Properties:
Temperature double returnTemperature/assignTemperature
Event sets:
Property Change Event
addPropertyChangeListener/removePropertyChangeListener
propertychange
Methods:
public void BeansBook.Simulator.Temperature.
assignTemperature(double)
public final void java.lang.Object.wait(long,int)
public void BeansBook.Simulator.Temperature.
removePropertyChangeListener
(java.beans.PropertyChangeListener)
public final native void java.lang.Object.notifyAll()
public double BeansBook.Simulator.Temperature.
returnTemperature()
public final void java.lang.Object.wait()
public java.lang.String java.lang.Object.toString()
public final native void java.lang.Object.notify()
public void BeansBook.Simulator.Temperature.
addPropertyChangeListener
(java.beans.PropertyChangeListener)
public native int java.lang.Object.hashCode()
public final native java.lang.Class
java.lang.Object.getClass()
public void BeansBook.Simulator.Temperature.
temperaturePulse
(BeansBook.Simulator.TemperaturePulseEvent)
public final native void java.lang.Object.wait(long)
public boolean java.lang.Object.equals(java.lang.Object)
- 241
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
9.
9.3
Introspection
Informationen über die Laufumgebung
Informationen über die Laufumgebung
Die Bean könnte auch über die Umgebung, in der sie sich gerade
befindet, interesssiert sein.
Sie könnte sich z.B. unterschiedlich verhalten, ob sie sich in einem
Entwicklungstool oder in einer Laufumgebung befindet.
Ein Entwicklungstool kann die Methode setDesignTime() der Klasse
java.beans.Beans aufrufen, um der Bean dies mitzuteilen.
Die Bean kann über isDesignTime() dies überprüfen.
Über die analogen Methoden setGuiAvailable() und isGuiAvailable()
kann die Bean feststellen, ob sie in einer graphischen Umgebung
läuft.
Es gibt weitere Methoden in dieser Richtung in der Schnittstelle
java.beans.Visibility.
Die BeanInfo Klassen des Simulators
s. Webpage zur Vorlesung
- 242
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
Property Editoren und Customizer
Property Editoren und Customizers
Wichtiges Feature von Komponenten
• Für visuelle Entwicklungswerkzeuge.
• Änderung von Eigenschaften und Verhalten der Komponenten.
Benutzerschnittstelle hierfür:
• Property Sheet mit allen Properties. jede Property mit ihrem Property
Editor.
Sind die Eigenschaften einer Komponenten komplexer, kann es
sinnvoll sein, eine spezielle Schnittstelle zum Anpassen der
Eigenschften zur Verfügung zu stellen:
• Customizers.
- 243
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
Visuelle Entwicklungswerkzeuge verwenden Property Sheets oder
ähnliches.
Siehe BeanBox.
Die PropertyEditor Schnittstelle
Property Editor:
Klasse zum Editieren einer Eigenschaft eines bestimmten Typs.
• primitiver Datentyp oder
• beliebige Klasse
Property Editoren müssen Schnittstelle java.beans.PropertyEditor
implementieren.
• Konsistentes Verhalten aller Property Editoren garantiert
Wie wird ein Property Editor mit einer bestimmten Eigenschaft
verknüpft?
Einfachste Technik:
Explizit als Teil der zugehörigen BeanInfo Klasse deklarieren.
Klasse java.beans.PropertyDesciptor enthält die Methode
setPropertyEditorClass(), um den zugehörigen Property Editor zu
identifizieren.
- 244
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
Demonstration der unterschiedlichen Techniken anhand der Boiler
Klasse.
Zunächst Basisklasse TemperatureModifier und dort die Eigenschaft
Running.
• In welcher BeanInfo Klasse soll der Editor deklariert werden,
- in der von TemperatureModifier oder
- von Boiler?
• Wir wählen die Superklasse, so daß die Information für alle
Nachfahren zur Verfügung steht.
Zunächst konzentrieren wir uns jedoch auf den Editor.
• Die Klasse soll BeansBook.Simulator.RunningEditor heißen.
• Sie implementiert das Interface java.beans.PropertyEditor.
• Die Klasse java.beans.PropertyEditorSupport macht das Leben
wieder etwas einfacher.
• Deshalb definieren wir unseren Editor direkt als Nachfahren dieser
Klasse:
RunningEditor (1/3)
// -- The first version of the RuningEditor class
package BeansBook.Simulator;
import java.beans.*;
public class RunningEditor extends PropertyEditorSupport {
// the current state of the property
protected boolean bRunning;
- 245
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
RunningEditor (2/3)
Jeder Property Editor implementiert setValue(). Ihm wird ein Object
übergeben, auch wenn die Eigenschaft nur ein primitiver datentyp ist,
wie hier.
Mittels getValue() wird das Ergebnis zurückgegeben.
// set the object being edited
public void setValue(Object o) {
// get the primitive data value from the object version
bRunning = ((Boolean)o).booleanValue();
}
// get the current value of the property
public Object getValue() {
// return the object version of the primitive type
return new Boolean(bRunning);
}
Unser Editor stellt die einfachste Form des Editierens zur Verfügung,
nämlich die über einen Textstring,
Nach einer Änderung wird ein Property Change Event gefeuert.
// get the value of the property as text
public String getAsText() {
if (bRunning) {
// return the text that indicates running
return "YES";
}
else {
// return the text that indicates not running
return "NO";
}
}
- 246
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
RunningEditor (3/3)
// set the value of the property as text
public void setAsText(String s) {
if (s.equals("YES")) {
// the state is running
bRunning = true;
}
else {
// the state is not running
bRunning = false;
}
}
}
// let any interested listeners know about the change
firePropertyChange();
- 247
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
TemperatureModifierBeanInfo
Bevor wir jetzt die Simulator.jar Datei neu erzeugen, müssen wir noch
die Klasse BeansBook.Simulator.TemperatureModifierBeanInfo
schreiben:
package BeansBook.Simulator;
import java.beans.*;
import java.lang.reflect.*;
public class TemperatureModifierBeanInfo
extends SimpleBeanInfo {
// return the property descriptors
public PropertyDescriptor[] getPropertyDescriptors() {
try {
// create a descriptor for the Rate property
PropertyDescriptor pd1 = new
PropertyDescriptor("Rate",
TemperatureModifier.class);
// create a descriptor for the Running property
PropertyDescriptor pd2 = new
PropertyDescriptor("Running",
TemperatureModifier.class);
// specify the property editor for Running
pd2.setPropertyEditorClass(RunningEditor.class);
// create an array of descriptors and
// return it to the caller
PropertyDescriptor[] pda = { pd1, pd2 };
return pda;
}
}
}
catch (Exception e) {
return null;
}
- 248
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
Editor für Running
Simulator.jar neu erzeugen:
• Zuvor muß Simulator.mft geändert werden.
• Wir müssen das folgende hinzufügen:
Name: BeansBook/Simulator/RunningEditor.class
Java-Bean: False
Name: BeansBook/Simulator/TemperatureModifierBeanInfo.class
Java-Bean: False
Der Property Editor für die Eigenschaft Running sieht dann wie folgt
aus:
Er stellt jetzt den Wert der booleschen Eigenschaft als Textstring dar.
• So muß er auch eingegeben werden, wobei die Schreibweise
natürlich genau einzuhalten ist.
- 249
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
Auswahlfeld für Running
Schöner wäre es, wenn man die richtigen Werte als Auswahl zur
Verfügung gestellt bekäme.
• Dazu stelle die Schnittstelle java.beans.PropertyEditor die Methode
getTags() zur Verfügung,
- welches ein Array von Strings zurückliefert,
- die alle legale Werte der Property sind.
Wir fügen also diese Methode zu BeansBook.Simulator.RunningEditor
hinzu.
// get the string tags
public String[] getTags() {
String[] s = { "YES", "NO" };
return s;
}
No sieht der Editor wie folgt aus:
Nicht alle Eigenschaften lassen sich als Text oder eine Aufzählung
darstellen. Liefert getAsText() ein null zurück, so weiß das Property
Sheet daß eine Darstellung als Text nicht möglich ist.
- 250
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
Eigene Darstellung für Running
(1/2)
Vollständige Übernahme der Darstellung:
• Löschen der Implementierungen von getAsText() und setAsText().
• Zwei Methoden, um den Wert der Eigenschaft selbst zu „malen“.
- isPaintable() sagt, ob der Editor den Wert selbst dartellen kann.
Der Defult-Wert ist false.
- paintValue():
- Als erster Parameter wird das java.awt.Graphics Objekt übergeben, auf das gezeichnet werden muß,
- der zweite Parameter ist ein java.awt.Rectangle, welches die
Größe der Fläche definiert.
Änderungen in der Klasse RunningEditor:
// indicate that we support paintValue
public boolean isPaintable() {
return true;
}
// implement the paintValue method
public void paintValue(Graphics gfx, Rectangle box) {
// the string variable that holds the string to draw
String s;
if (bRunning) {
// if running we paint YES
s = "YES";
}
else {
// if not running we paint NO
s = "NO";
}
- 251
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
Eigene Darstellung für Running
(2/2)
// set the background color to white
gfx.setColor(Color.white);
// fill the rectangle with the background color
gfx.fillRect(box.x, box.y, box.width, box.height);
// set the color to black for drawing text
gfx.setColor(Color.black);
// find a reasonable place to draw the string based
// on the font
FontMetrics fm = gfx.getFontMetrics();
int w = fm.stringWidth(s);
int x = box.x + (box.width - w) / 2;
int y = box.y + box.height / 2;
}
// draw the string that represents the value of
// the property
gfx.drawString(s, x, y);
Dies ist aber bisher nur die Darstellung. Damit kann der Wert noch
nicht geändert werden.
Dazu müssen wir einen eigenen Editor zur Verfügung stellen. Daß wir
das tun, zeigen wir durch die Methode supportsCustomEditor() an, die
jetzt true liefern muß.
Die Methode getCustomEditor() muß dann die Instanz des Editors
liefern.
• Das Ergebnis ist vom Typ java.awt.Component.
• Also muß der Editor ein Nachfahre dieser Klasse sein (tatsächlich
ist er ein Panel).
• Unser Editor heißt BeansBook.Simulator.RunningPanel.
- 252
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
Eigener Editor für Running
// we support a custom editor
public boolean supportsCustomEditor() {
return true;
}
// return the custom editor
public Component getCustomEditor() {
// create an instance of the custom editor
return new RunningPanel(this);
}
- 253
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
Der Editor für Running (1/2)
• Der Editor RunningPanel ist Bestandteil desselben Packages, da er
sonst nirgends eingesetzt werden soll.
• Er wird als nicht public definiert und ist Bestandteil der
RunningEditor.java Datei.
• Als Benutzerschnittstelle werden zwei Buttons (YES und NO)
verwendet:
...
class RunningPanel extends Panel implements ActionListener {
// create the YES button
protected Button yes = new Button("YES");
// create the NO button
protected Button no = new Button("NO");
// the instance of the editor that we’re working for
protected RunningEditor editor;
// the constructor
public RunningPanel(RunningEditor ed) {
// save a reference to the editor we’re working for
editor = ed;
// set the size of the buttons to 50 x 50
yes.setSize(50,50);
no.setSize(50,50);
// add the buttons to the panel
add(yes);
add(no);
}
// become an action listener for the yes and no buttons
yes.addActionListener(this);
no.addActionListener(this);
- 254
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren
Eigener Editor für Running
(2/2)
// handle the action performed event
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == yes) {
// tell the editor about the new value
editor.setValue(new Boolean(true));
}
else {
// tell the editor about the new value
editor.setValue(new Boolean(false));
}
}
}
// tell the editor to fire a property change event to
// it’s listeners
editor.firePropertyChange();
Nachdem die Datei Simulator.mft um
Name: BeansBook/Simulator/RunningPanel.class
Java-Bean: False
ergänzt wurde sieht der Editor nun wie folgt aus:
- 255
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Der Custom Property Editor kommt in Gestalt einer modalen
Dialogbox, die von der BeanBox erzeugt wird.
- 256
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren finden
Wir haben den Bezug zu dem richtigen Property Editor in der
entsprechenden BeanInfo Klasse gemacht.
• Aber nicht jede Bean mag eine eigene BeanInfo Klasse bereitstellen.
• Geschickter wäre es, wir könnten für einen bestimmten PropertyTyp den geeigneten Editor angeben.
- In der Tat funktioniert die BeanBox so.
- Z.B. gibt es für alle Properties von Typ boolean einen geeigneten
Editor.
Wir erstellen zunächst die Klasse Running, um diesen „Datentyp“ zu
definieren:
package BeansBook.Simulator;
public class Running {
// the value of the running object
protected boolean bRunning;
// constructor
public Running(boolean b) {
// save the state
bRunning = b;
}
}
// return the value of the object
public boolean value() {
return bRunning;
}
- 257
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Property Editoren finden
Notwendige Änderungen des
Simulators
Durch die Einführung dieses neuen Datentyps müssen etliche
Änderungen an unseren Simulatorklassen durchgeführt werden:
• In der Klasse TemperatureModifier muß für die Methode
setRunning() der Parametertyp von boolean auf Running geändert
werden
• Die Methode isRunning() derselben Klasse muß in getRunning()
umbenannt und ebenfalls an den neuen Datentyp angepaßt werden.
• In den Klassen Cooler und Boiler müssen die Methoden
coolingRequest() und heatingRequest() auf den geänderten
Datentyp umgestellt werden, da diese die Methode setRunning() der
Basisklasse aufrufen.
• Die Klasse RunningEditor muß geändert werden, damit dort anstelle
boolean ebenfalls Running benutzt wird. Dies betrifft die methoden
setValue() und getValue().
• Der Custom Property Editor RunningPanel muß ebenfalls auf Running
umgestellt werden. In actionPerformed() wird setValue() aufgerufen
und muß nun den geänderten Parametertyp aufnehmen.
Mit diesen Änderungen funktioniert der Simulator wie zuvor.
Aber das war nur die Vorbereitung.
- 258
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Einen Property Editor registrieren
In der TemperatureModifierBeanInfo Klasse führen wir eine geringe
Änderung durch.
• Dort spezifizierten wir den Editor mit der Methode
setPropertyEditorClass() für eine bestimmte Property Descriptor
Variable (pd2).
• Wir löschen diesen Aufruf und verwenden eine andere Methode, um
den richtigen Editor zu finden.
Ist der zugehörige Editor in dem entsprechenden Property Descriptor
nicht definiert, so wird die Klasse java.beans.PropertyEditorManager
benutzt, um den richtigen Editor zu finden.
Dabei werden mehrere Techniken verwendet.
• Die erste basiert auf der Registrierung eines Editors für einen
bestimmten Datentyp (Klasse).
• Dies geschieht mit der Methode registerEditor().
- Sie besitzt zwei Parameter: Die Klasse des Property Typs und die
Klasse des Editors.
- Die Deregistrierung für einen bestimmten Property Typ findet hier
durch die Übergabe von null für die Editor Klasse statt(!).
- 259
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Einen Property Editor registrieren
Die Registrierung gilt nur zur Laufzeit, sie wird nirgends permanent
gespeichert.
Wir ergänzen die Running Klasse um die Registrierung:
// -- The second version of the Running class
package BeansBook.Simulator;
public class Running {
// Initialize the class
static {
// register a property editor for the Running object
java.beans.PropertyEditorManager.registerEditor(
Running.class, RunningEditor.class);
}
// the value of the running object
protected boolean bRunning;
// constructor
public Running(boolean b) {
// save the state
bRunning = b;
}
}
// return the value of the object
public boolean value() {
return bRunning;
}
- 260
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.1
Property Editoren und Customizer
Property Editoren
Einen Property Editor registrieren
Weitere Technik
Eine weitere Technik ist es, wieder bestimmte Namenskonventionen
zu befolgen.
• Ist für einen bestimmten Typ kein Editor registriert, sucht der
Property Editor Manager in demselben Package nach einer
gleichnamigen Klasse mit dem String „Editor“ angehängt.
• Wir haben diese Namenskonvention offenbar schon eingehalten:
- Typ Klasse: Running
- Editor Klasse: RunningEditor
• Wir könnten also den static Block aus der Klasse Running
entfernen.
Default Pfad
Wird der Property Editor Manager hierbei nicht fündig, sucht er nach
obiger Namenskonvention in einem Default Pfad.
• Dies ist sun.beans.editors.
• Hier befinden sich bereits die Default Editoren für die primitiven
Datentypen sowie für java.awt.Color, java.awt.Font und
java.lang.String.
Dieser Pfad kann gelesen und geändert werden mit
• getEditorSearchPath() und
• setEditorSearchPath().
Mit letzterer Methode können auch mehrere Pfade angegeben werden
(interessant für Tool-Hersteller).
- 261
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizers
Benutzerschnittstelle, um eine komplette Bean anzupassen, nicht nur
eine einzelne Eigenschaft.
• Hierbei können auch andere Charakteristiken der Bean angepaßt
werden, nicht nur die veröffentlichten Properties.
• Selbst „Assistenten“ sind möglich.
Voraussetzung für Customizer: BeanInfo Klasse.
• Kann auch nur eine triviale sein.
• Keine feste Namenskonvention für Customizerklassen.
• Kein Customizer Manager, um einen Customizer für bestimmte
Klassen zu registrieren.
Im Prinzip kann ein Customizer auch zur Run-Time zur Verfügung
getellt werden, dann vielleicht mit reduziertem Funktionsumfang.
Einfachste Art, Customizer zu deklarieren:
• Trivialen Bean Descriptor implementieren
• Dessen Konstruktor nimmt als zweiten Parameter die Customizer
Klasse auf
- 262
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse
Über Bean Descriptor bekannt
machen
public BeanDescriptor getBeanDescriptor() {
// create the bean descriptor object
BeanDescriptor bd = new BeanDescriptor(Boiler.class,
BoilerCustomizer.class);
// set the display name
bd.setDisplayName("Simulated Boiler");
}
// return the descriptor object
return bd;
- 263
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse
Klasse BeansBook.Simulator.BoilerCustomizer
Voraussetzungen
• Alle Bean Customizer müssen das java.beans.Customizer Interface
implementieren. Hat nur drei Methoden:
- Übliche addPropertyChangeListener() und removePropertyChangeListener() Methoden, um die Änderungen den Listener Objekten
mitteilen zu können.
- Methode setObject() mit java.lang.Object als Parametertyp. Parameter repräsentiert die Bean, die angepaßt werden soll.
• Customizer muß Nachfahre von java.awt.Component sein.
- Damit kann der Customizer zu einem Panel oder einer Dialogbox
hinzugefügt werden.
• Er muß Default-Konstruktor zur Verfügung stellen
- Er wird über einen Aufruf von newInstance() der Klasse
java.lang.Class erzeugt.
Anforderungen an Boiler
Customizer
• Die Werte der Properties Rate und Running können verändert
werden.
• Der Konstruktor der Klasse Boiler ruft den Konstruktor der
Vorfahrenklasse mit einigen Parametern auf, die auch anpaßbar
sein sollen, z.B. die Arbeitstemperatur (100 °C).
- 264
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse
Änderungen an
TemperatureModifier
Arbeitstemperatur ändern:
• Modifikation der Vorfahrenklasse TemperatureModifier um
Methoden, um diese Eigenschaft schreiben und lesen zu können.
• Da diese Methoden nicht mit Property set- und get-Methoden
verwechselt werden sollen, geben wir ihnen nicht den
Namenskonventionen entsprechende Namen:
// set the operating temperature
public void assignOperatingTemperature(double t) {
temp = t;
}
// get the operating temperature
public double retrieveOperatingTemperature() {
return temp;
}
Weiterer Parameter ist Farbe, die die Komponente als „on“
kennzeichnet:
// set the "on" color
public void assignOnColor(Color c) {
onColor = c;
if (running) {
setBackground(onColor);
}
}
// get the "on" color
public Color retrieveOnColor() {
return onColor;
}
- 265
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse
Änderungen an Boiler
Es kann passieren, daß, nachdem die gewünschte
Umgebungstemperatur erreicht wurde, die Boiler Temperatur
niedriger als diese gesetzt wird.
• Selbst wenn dann die gewünschte Temperatur 1 Grad niedriger
gesetzt wird, würde es zu Vetos kommen.
• Dies muß verhindert werden, indem die vetoableChange() Methode
der Klasse Boiler angepaßt wird:
public void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException {
// only interested in ComfortTemperature
if (evt.getPropertyName().equals("ComfortTemperature")) {
// get the proposed temperature
Double d = (Double)evt.getNewValue();
// get the old value
Double old = (Double)evt.getOldValue();
// determine if the temperature is increasing
boolean bIncreasing = (d.doubleValue() >
old.DoubleValue());
}
}
// veto a rising temperature over the operating
// temperature
if (bIncreasing && d.doubleValue() >
retrieveOperatingTemperature()) {
throw new PropertyVetoException(
"Invalid Comfort Temperature", evt);
}
- 266
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse (1/8)
Es gibt keine Support-Klasse.
Wir müssen „from scratch“ beginnen.
Benutzerschnittstelle
• Choice Liste für Running
• Text Field für Rate und die Operating Temperature
• Color Property Editor, um die Darstellungsfarbe für den aktiven
Bolier zu wählen
Vorgänger und Schnittstellen
• Klasse erweiter java.awt.Panel und implementiert java.beans.Customizer.
• Implementiert die Schnittstellen java.awt.ItemListener und
java.awt.ActionListener.
• Ein Text Field feuert ein actionPerformed Ereignis, wenn Enter
gedrückt wurde (keine Reaktion auf jede einzelne Eingabe).
• PropertyChangeListener Interface wird gebraucht, um die Property
Change Events von dem Color Property Editor zu behandeln.
package BeansBook.Simulator;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
public class BoilerCustomizer
implements Customizer,
ItemListener,
ActionListener
PropertyChangeListener
extends Panel
// to be a bean customizer
// to handle Choice list events
// to handle action events
// color property changes
{
- 267
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse (2/8)
Attribute
// the boiler that we are customizing
protected Boiler theBoiler;
// an instance of property change support
protected PropertyChangeSupport support;
// the Choice list for the Running property
protected Choice runningChoice = new Choice();
// a text field for the Rate property
protected TextField rateField = new TextField("*******");
// a text field for the operating temperature
protected TextField tempField = new TextField("*******");
// the property editor for the running color
protected PropertyEditor colorEditor;
Der Color Property Editor wird erst zur Laufzeit gefunden.
Der Konstruktor erzeugt alle nötigen Objekte und fügt sie, falls
angebracht, dem Panel zu.
- 268
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse (3/8)
public BoilerCustomizer() {
// Empty Constructor
// create the instance of the support object
support = new PropertyChangeSupport(this);
// add a label for the Running property
add(new Label("Running State: "));
// add the Running property choice list
add(runningChoice);
// add a label for the Rate property
add(new Label("Pulse Rate: "));
// add the Rate property field
add(rateField);
// add a label for the operating temperature
add(new Label("Operating Temp: "));
// add the operating temperature field
add(tempField);
// add a label for the color editor
add(new Label("Running Color: "));
// find custom editor and add it to the panel
colorEditor = PropertyEditorManager.findEditor(
java.awt.Color.class);
add(colorEditor.getCustomEditor());
// add the choice strings to the Running choice
runningChoice.add("NO");
runningChoice.add("YES");
// become an item listener for the Choice list
runningChoice.addItemListener(this);
// become an action listener for the edit fields
rateField.addActionListener(this);
tempField.addActionListener(this);
}
- 269
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse (4/8)
setObject()
Das setObject() übergebene Objekt ist die anzupassende Bean, also
unsere Boiler Instanz.
Wir fragen die einzelnen Eigenschaften und Zustände ab und setzen
die Benutzerschinittstellen entsprechend.
public void setObject(Object o) {
// save a reference to the bean we're customizing
theBoiler = (Boiler)o;
// get the state of the Running property and select it
// in the Choice list
if (theBoiler.getRunning().value()) {
runningChoice.select("YES");
}
else {
runningChoice.select("NO");
}
// put the current value of the Rate property
// into the field
int rate = theBoiler.getRate();
rateField.setText(String.valueOf(rate));
// put the current value of the operating temperature
// into the field
double temp = theBoiler.retrieveOperatingTemperature();
tempField.setText(String.valueOf(temp));
// hookup the color editor
colorEditor.setValue(theBoiler.retrieveOnColor());
}
// prepare to receive property change Events
colorEditor.addPropertyChangeListener(this);
- 270
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse (5/8)
Property Change Registrierung
Prepariere die Registrierungsmethode für die eigenen Property
Changes
public void addPropertyChangeListener(
PropertyChangeListener l) {
// defer to the support object
support.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(
PropertyChangeListener l) {
// defer to the support object
support.removePropertyChangeListener(l);
}
getPrefferedSize()
Im folgenden wird neben getPrefferedSize() auch noch die deprecated
Version preferredSize() implementiert, da die BeanBox, wenigstens
ältere Versionen davon, noch diese alte Methode aufruft.
public Dimension preferredSize() {
// defer to the getPreferredSize method
return getPreferredSize();
}
public Dimension getPreferredSize() {
// we prefer a dimension of 480 by 80
return new Dimension(480, 80);
}
- 271
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse (6/8)
itemStateChanged()
// handle an item state changed event
public void itemStateChanged(ItemEvent evt) {
// if a new selection is made in the
// Running choice list...
if (evt.getSource() == runningChoice &&
evt.getStateChange() == ItemEvent.SELECTED)
// get the instance of the choice list
Choice pp = (Choice)evt.getSource();
{
// determine the newly selected item string
String sel = pp.getSelectedItem();
// the desired boolean state of the Running property
boolean state;
if (sel.equals("YES")) {
state = true;
}
else {
state = false;
}
// create a new instance of Running
Running newState = new Running(state);
// set the Running property of the boiler bean
theBoiler.setRunning(newState);
}
// fire a Running property change event
support.firePropertyChange("Running", null,
newState);
}
- 272
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse (7/8)
actionPerformed()
actionPerformed() wird aufgerufen, wenn der Benutzer Enter gedrückt
hat. Dies geschieht entweder in dem Rate Feld oder in dem Feld für
die Operating Temperature.
// handle an actionPerformed event
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == rateField) {
// the event came from the rate field
// get the text from the field
String s = rateField.getText();
// get an integer representation of the new value
int r = Integer.valueOf(s).intValue();
// set the Rate property
theBoiler.setRate(r);
// fire an unspecified property change event
// the listener has to figure out what happened
support.firePropertyChange("", null, null);
}
else {
// the event came from the operating temp field
// get the text from the field
String s = tempField.getText();
// get a double representation of the new value
double r = Double.valueOf(s).doubleValue();
// set the new operating temperature
theBoiler.assignOperatingTemperature(r);
}
}
- 273
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
10.
10.2
Property Editoren und Customizer
Customizers
Customizer für Boiler Klasse (8/8)
propertyChange()
Reagiert auf Änderung im Color Editor.
}
}
public void propertyChange(PropertyChangeEvent evt) {
Color c = (Color)colorEditor.getValue();
theBoiler.assignOnColor(c);
Erweiterung der Manifest-Datei:
Name: BeansBook/Simulator/BoilerCustomizer.class
Java-Bean: False
JAR Datei erstellen.
Customizer kann in BeanBox durch Selektieren der Bean und Aufruf
von „Edit/Customize“ in der Menüleiste aktiviert werden:
- 274
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.1
Reflection und Introspection nutzen
Beispielanwendung BeanTool
Reflection und Introspection nutzen
Beispielanwendung BeanTool
Benutzeroberfläche:
• Ein leeres Fenster.
• Hier hinein können Beans hinzugefügt werden.
• Diese können miteinander verbunden werden.
Einschränkungen:
• Alle zu verwendenden Beans müssen sich in dem Verzeichnis
beantool\jars befinden.
• Nur Nachfahren der Klasse java.lang.Component werden behandelt.
• Beans müssen visible sein und können keine Applets sein.
• Beans sind – in diesem Beispiel noch – nicht konfugurierbar.
Es gibt einen Dialog, um Beans auszuwählen:
- 275
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.1
Reflection und Introspection nutzen
Beispielanwendung BeanTool
Beispielanwendung BeanTool
Und einen Dialog, um Beans zu verbinden:
Der Quellcode:
Klasse
AddDialog
Bean
BeanInstance
BeanTool
ConnectDialog
Jar
JarClassLoader
Beschreibung
Stellt Dialogbox dar, mit deren Hilfe die Bean
ausgesucht wird, die in den Layout Bereich
eingefügt werden soll
Namen der verfügbaren Beans
Informationen über eine Bean-Instanz in dem
Layout Bereich
Hauptprogramm. Stellt Layout Bereich zur
Verfügung
Stellt Dialogbox dar, mit deren Hilfe zwei Beans
in dem Layout Bereich miteinander verknüpft
werden können
Verarbeitet die Einträge einer Jar-Datei
Lädt .class Einträge aus den Jar-Dateien
- 276
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.2
Reflection und Introspection nutzen
Klasse BeanTool
Klasse BeanTool (1/3)
package beantool;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.*;
public class BeanTool extends Frame {
private int x, y;
// coordinates of mouse when clicked
private Object bean1; // first bean to be connected
// (event source)
public static void main(String args[]) {
Jar.process();
// process JAR files
new BeanTool();
}
public BeanTool() {
super("Bean Tool");
addMouseListener(new MyMouseAdapter());
addWindowListener(new MyWindowAdapter());
setSize(400, 400);
setVisible(true);
}
class MyMouseAdapter extends MouseAdapter {
// catch mouse clicked only
public void mouseClicked(MouseEvent me) {
x = me.getX();
y = me.getY();
if(me.isAltDown()) {
add();
}
else if(me.isShiftDown()) {
connect();
}
repaint();
}
}
- 277
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.2
Reflection und Introspection nutzen
Klasse BeanTool
Klasse BeanTool (2/3)
class MyWindowAdapter extends WindowAdapter {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
}
public void add() {
new AddDialog(this);
// select and add a bean
bean1 = null;
}
public void connect() {
// connect two beans
BeanInstance bi = selectBeanInstance();
if(bi != null) {
if(bean1 == null) {
bean1 = bi.getBean();
return;
}
Object bean2 = bi.getBean();
new ConnectDialog(this, "Title", bean1, bean2);
}
bean1 = null;
}
public BeanInstance selectBeanInstance() {
// Determine which component is being selected by mouse
Vector v = BeanInstance.getBeanInstances();
Enumeration e = v.elements();
while(e.hasMoreElements()) {
BeanInstance bi = (BeanInstance)e.nextElement();
Component c = (Component)bi.getBean();
Point p = c.getLocation();
Dimension d = c.getSize();
Rectangle r =
new Rectangle(p.x, p.y - 10, d.width - 1, 10);
if(r.contains(x, y)) {
return bi;
}
}
return null;
}
- 278
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.2
Reflection und Introspection nutzen
Klasse BeanTool
Klasse BeanTool (3/3)
public void doLayout() {
// Layout all of the components
Vector v = BeanInstance.getBeanInstances();
Enumeration e = v.elements();
while(e.hasMoreElements()) {
BeanInstance bi = (BeanInstance)e.nextElement();
Component c = (Component)bi.getBean();
Dimension d = c.getPreferredSize();
c.setBounds(bi.getX(), bi.getY(), d.width, d.height);
c.doLayout();
}
}
public void insertBean(String beanName) {
// Create a new instance of the Bean
// named beanName; add to static Vector of BeanInstance
BeanInstance bi = new BeanInstance(this, beanName, x, y);
}
}
// Layout all components
doLayout();
- 279
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.3
Reflection und Introspection nutzen
Klasse Jar
Klasse Jar (1/4)
Für jede .class Datei in der JAR Datei, die eine Bean ist, wird eine
Bean Instanz erzeugt.
package beantool;
import java.io.*;
import java.util.*;
import java.util.zip.*;
public class Jar {
private static Hashtable data = new Hashtable();
private String filename;
public static void putData(String clsName, byte[] buffer) {
data.put(clsName, buffer);
}
public static Object getData(String clsName) {
return data.get(clsName);
}
public static void process() {
try {
char c = File.separatorChar;
File dir = new File("beantool" + c + "jars");
String entries[] = dir.list();
for(int i = 0; i < entries.length; i++) {
if(entries[i].endsWith(".jar")) {
new Jar("beantool" + c + "jars" + c + entries[i]);
}
}
}
catch(Exception ex) {
ex.printStackTrace();
}
}
- 280
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.3
Reflection und Introspection nutzen
Klasse Jar
Klasse Jar (2/4)
public Jar(String filename) {
// Read and process the .class entries in the JAR file
this.filename = filename;
try {
FileInputStream fis = new FileInputStream(filename);
ZipInputStream zis = new ZipInputStream(fis);
ZipEntry ze = null;
while((ze = zis.getNextEntry()) != null) {
String name = ze.getName();
if(name.equals("META-INF/MANIFEST.MF")) {
processManifestFile(zis);
}
else if(name.endsWith(".class")) {
processClassFile(name, zis);
}
}
zis.close();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
- 281
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.3
Reflection und Introspection nutzen
Klasse Jar
Klasse Jar (3/4)
private void processManifestFile(ZipInputStream zis) {
try {
// Create a BufferedReader for the zip input stream
InputStreamReader isr = new InputStreamReader(zis);
BufferedReader br = new BufferedReader(isr);
// Read lines
// and create
String name =
String line =
while((line =
from the manifest file
Bean objects
null;
null;
br.readLine()) != null) {
// Process lines starting with .class
if(line.startsWith("Name: ") &&
line.endsWith(".class")) {
name = line.substring(line.indexOf(":") + 2);
}
else if(line.startsWith("Java-Bean: ")) {
if(name != null) {
// Determine class name
String name2 = name.replace('/', '.');
int i = name2.indexOf(".class");
name2 = name2.substring(0, i);
}
}
}
// Create a Bean object for that class
new Bean(name2);
name = null;
}
catch(Exception ex) {
ex.printStackTrace();
}
}
- 282
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.3
Reflection und Introspection nutzen
Klasse Jar
Klasse Jar (4/4)
private void processClassFile(String name1,
ZipInputStream zis) {
// Determine class name
String name2 = name1.replace('/','.');
int i = name2.indexOf(".class");
if(i != -1) {
name2 = name2.substring(0, i);
}
try {
// Read bytecodes from the zip input stream
ByteArrayOutputStream baos =
new ByteArrayOutputStream();
for(;;) {
byte block[] = new byte[1024];
int len = zis.read(block);
if(len < 0) {
break;
}
baos.write(block, 0, len);
}
byte buffer[] = baos.toByteArray();
// Save these bytecodes
putData(name2, buffer);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
}
- 283
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.4
Reflection und Introspection nutzen
Klasse JarClassLoader
Klasse JarClassLoader (1/2)
package beantool;
public class JarClassLoader extends ClassLoader {
public static JarClassLoader singleton =
new JarClassLoader();
protected Class loadClass(String clsName, boolean resolve)
throws ClassNotFoundException {
// Check the System class loader
Class cls;
try {
cls = super.findSystemClass(clsName);
return cls;
}
catch(ClassNotFoundException ex) {
}
catch(NoClassDefFoundError err) {
}
// Check if this class has already
// been loaded
cls = findLoadedClass(clsName);
if(cls != null) {
return cls;
}
// Get the bytecodes for this class
byte buffer[] = (byte[])Jar.getData(clsName);
if(buffer == null) {
throw new ClassNotFoundException();
}
// Parse the data
cls = defineClass(clsName, buffer, 0, buffer.length);
if(cls == null) {
throw new ClassFormatError();
}
- 284
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.4
Reflection und Introspection nutzen
Klasse JarClassLoader
Klasse JarClassLoader (2/2)
// Resolve the class if necessary
if(resolve) {
resolveClass(cls);
}
}
}
// Return the class
return cls;
- 285
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.5
Reflection und Introspection nutzen
Klasse Bean
Klasse Bean
package beantool;
import java.util.*;
public class Bean {
private static Vector beans = new Vector();
private String name;
public static Vector getBeans() {
return beans;
}
public Bean(String name) {
this.name = name;
beans.addElement(this);
}
}
public String getName() {
return name;
}
- 286
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.6
Reflection und Introspection nutzen
Klasse AddDialog
Klasse AddDialog (1/2)
package beantool;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class AddDialog extends Dialog
implements ItemListener {
private BeanTool beanTool;
private java.awt.List list;
public AddDialog(BeanTool beanTool) {
// Invoke superclass constructor
super(beanTool, "Add Dialog", true);
// Initialize beanTool
this.beanTool = beanTool;
// Create and initialize list
// and add it to dialog box
list = new java.awt.List();
initializeList();
list.addItemListener(this);
add("Center", list);
// Register to receive window events
addWindowListener(new MyWindowAdapter());
}
// Set size of dialog and make it visible
setSize(200, 200);
show();
- 287
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.6
Reflection und Introspection nutzen
Klasse AddDialog
Klasse AddDialog (2/2)
private void initializeList() {
// Initialize list
Vector beans = Bean.getBeans();
Enumeration e = beans.elements();
while(e.hasMoreElements()) {
Bean bean = (Bean)e.nextElement();
list.add(bean.getName());
}
}
public void itemStateChanged(ItemEvent ie) {
// Process list selection
String beanName = list.getSelectedItem();
beanTool.insertBean(beanName);
dispose();
}
}
class MyWindowAdapter extends WindowAdapter {
public void windowClosing(WindowEvent we) {
dispose();
}
}
- 288
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.7
Reflection und Introspection nutzen
Klasse BeanInstance
Klasse BeanInstance (1/2)
Ein BeanIstance Objekt für jede Bean im Layout Bereich. Referenz zur
Komponenten und Koordinaten im Layout Bereich.
package beantool;
import java.awt.*;
import java.beans.*;
import java.util.*;
public class BeanInstance {
private static Vector beanInstances = new Vector();
private Object bean;
private int x, y;
public static Vector getBeanInstances() {
return beanInstances;
}
public BeanInstance(BeanTool beanTool,
String beanName, int x, int y) {
// Save the location of the component
this.x = x;
this.y = y;
// Instantiate the component named beanName
try {
bean = Beans.instantiate(JarClassLoader.singleton,
beanName);
}
catch(Exception ex) {
return;
}
// Ignore invisible components
if(!Beans.isInstanceOf(bean, Component.class)) {
return;
}
- 289
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.7
Reflection und Introspection nutzen
Klasse BeanInstance
Klasse BeanInstance (2/2)
// Add the component to beanInstances
beanInstances.addElement(this);
// Position and layout the component
Component c = (Component)bean;
c.setLocation(x, y);
c.doLayout();
}
// Add the component to the BeanTool frame
beanTool.add(c);
public Object getBean() {
return bean;
}
public int getX() {
return x;
}
}
public int getY() {
return y;
}
- 290
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.8
Reflection und Introspection nutzen
Klasse ConnectDialog
Klasse ConnectDialog (1/3)
package beantool;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.lang.reflect.*;
import java.util.*;
public class ConnectDialog extends Dialog
implements ItemListener {
private Object bean1, bean2;
private java.awt.List list;
EventSetDescriptor esds[];
public ConnectDialog(Frame frame, String title,
Object bean1, Object bean2) {
// Invoke superclass constructor
super(frame, "Connect Dialog", true);
// Save bean1 and bean2
this.bean1 = bean1;
this.bean2 = bean2;
// Create and initialize list
list = new java.awt.List();
initializeList();
list.addItemListener(this);
add("Center", list);
// Register to receive window events
addWindowListener(new MyWindowAdapter());
// Set size of dialog and make it visible
setSize(200, 200);
show();
}
- 291
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.8
Reflection und Introspection nutzen
Klasse ConnectDialog
Klasse ConnectDialog (2/3)
private void initializeList() {
// Get the BeanInfo object for bean1
Class cls1 = bean1.getClass();
BeanInfo bi1;
try {
bi1 = Introspector.getBeanInfo(cls1);
}
catch(Exception ex) {
return;
}
}
// Get the EventSetDescriptor objects for
// bean1 and add these to the list
esds = bi1.getEventSetDescriptors();
for(int i = 0; i < esds.length; i++) {
list.add(esds[i].getName());
}
- 292
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.8
Reflection und Introspection nutzen
Klasse ConnectDialog
Klasse ConnectDialog (3/3)
public void itemStateChanged(ItemEvent ie) {
// Obtain the EventSetDescriptor object
int index = list.getSelectedIndex();
EventSetDescriptor esd = esds[index];
// Obtain the registration method
Method method = esd.getAddListenerMethod();
// Invoke the registration method of
// bean1 to register bean2
Object args[] = new Object[1];
args[0] = bean2;
try {
method.invoke(bean1, args);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
}
// Dispose of this dialog box
dispose();
class MyWindowAdapter extends WindowAdapter {
public void windowClosing(WindowEvent we) {
dispose();
}
}
- 293
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.9
Reflection und Introspection nutzen
Introspection Szenarien
Introspection Szenarien
Ereignisse der Bean feststellen
Wie kann eine Anwendug dynamisch feststellen, welche Ereignisse
eine Bean erzeugen kann?
1. Wir rufen getBeanInfo() der Klasse Introspector auf, um ein Objekt
zu erhalten, das das BeanInfo Interface implementiert.
Dies wird via Reflection im Flug von Introspector erzeugt
(Namensdkonventionen sind eingehalten, keine eigene BeanInfo
Klasse).
2. Über getEventSetDescriptor() von BeanInfo erhalten wir einArray
von EventSetDescriptor Objekten.
Jedes dieser Objekte enthält Metadaten zu einem Event Set.
3. Wir fragen nach dem Default Event der Bean.
4. Über dessen Index erhalten wir die Klasse (Typ Class) des Listener
Interfaces dieser Klasse.
5. Über getListenerMethods() des Default Event Set Descriptors
erhalten wir ein Array mit den Methoden dieser Schnittstelle (Method
Objekte).
6. Erhalte die AddListener und RemoveListener Methoden für diese
Schnittstelle.
7. Finde heraus, ob das Ereignis ein Unicast Ereignis ist.
- 294
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.9
Reflection und Introspection nutzen
Introspection Szenarien
Introspection Szenarien
Ereignisse der Bean feststellen
Application
Introspector
getBeanInfo(MyBean.class)
BeanInfo
getEventSetDesciptors
EventSetDesciptor[ ]
getDefaultEventIndex
getListenerType
getListenerMethods
getAddListenerMethod
getRemoveListenerMethod
isUnicast
• Es kann auf diesem Weg noch wesentlich mehr an Informationen
gefunden werden.
• Im Prinzip wird immer zuerst das BeanInfo Objekt gefunden oder
erzeugt.
• Dieses stellt dann die weiteren Informationen zur Verfügung.
- 295
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.9
Reflection und Introspection nutzen
Introspection Szenarien
Introspection Szenarien
Property-Werte der Bean
feststellen
Wir stellen die Properties einer Bean fest und holen uns den Wert
einer Property über deren Zugriffsmethode.
1. Wir beginnen wieder damit, das BeanInfo Objekt zu erhalten.
2. Wir fragen nach der Property Deskriptoren der Bean.
3. Wir erfragen die Default Property.
4. Über deren Index erhalten wir die Lesemethode dieser Eigenschaft
als Objekt der Klasse Method.
5. Mit Hilfe der Methode invoke() der Klasse Method rufen wir die
Zugriffsmethode auf und erhalten den Wert der Property.
Diese Methode wird weitgehend von Entwicklungswerkzeugen
eingesetzt.
Application
Introspector
getBeanInfo(MyBean.class)
BeanInfo
getPropertyDesciptors
PropertyDesciptor[ ]
getDefaultPropertyIndex
getReadMethod
Method
invoke
- 296
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.9
Reflection und Introspection nutzen
Introspection Szenarien
Bean Analyse Programm (1/3)
import java.beans.*;
import java.awt.*;
import java.lang.reflect.*;
public class BeanAnalyst {
static public void main(String args[]) {
try {
// Instantiate a bean
Object s = Beans.instantiate(null, args[0]);
// Introspect on class and stop at direct parent class
BeanInfo bi = Introspector.getBeanInfo(s.getClass(),
s.getClass().getSuperclass());
// Discover the display name
BeanDescriptor bdsc = bi.getBeanDescriptor();
System.out.println("Hi! Your display name is = " +
bdsc.getDisplayName());
// Get the bean's properties
PropertyDescriptor[] pd = bi.getPropertyDescriptors();
System.out.println("\n\nYour properties are: \n");
for (int i = 0; i < pd.length; i++) {
System.out.println("property = " + pd[i].getName() +
" (write method = " +
pd[i].getWriteMethod().getName() +
", read method = " +
pd[i].getReadMethod().getName() + ")");
}
// Get the bean's methods
MethodDescriptor[] md = bi.getMethodDescriptors();
System.out.println("\n\nYour methods are: \n");
for (int i = 0; i < md.length; i++) {
System.out.println("" + md[i].getMethod() );
}
- 297
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.9
Reflection und Introspection nutzen
Introspection Szenarien
Bean Analyse Programm (2/3)
// Get the bean's events
EventSetDescriptor[] evsd = bi.getEventSetDescriptors();
Method[] evm = evsd[0].getListenerMethods();
System.out.println(
"\n\nYou emit the following Events: \n");
for (int i = 0; i < evm.length; i++) {
System.out.println("" + evm[i].getName() );
}
// Get the bean's icon types
System.out.println(
"\n\nYou provide the following icon types: \n");
if (bi.getIcon(BeanInfo.ICON_COLOR_32x32) != null)
System.out.println("32x32 color");
if (bi.getIcon(BeanInfo.ICON_COLOR_16x16) != null)
System.out.println("16x16 color");
if (bi.getIcon(BeanInfo.ICON_MONO_32x32) != null)
System.out.println("32x32 mono");
if (bi.getIcon(BeanInfo.ICON_MONO_16x16) != null)
System.out.println("16x16 mono");
if (Beans.isDesignTime())
System.out.println(
"\n\nYour bean is in design-time mode.");
else
System.out.println(
"\n\nYour bean is in run-time mode.");
if (Beans.isGuiAvailable())
System.out.println("A GUI is available to your bean.");
else
System.out.println(
"A GUI is not available to your bean.");
- 298
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.9
Reflection und Introspection nutzen
Introspection Szenarien
Bean Analyse Programm (2/3)
// Are you a persistent bean?
Class myClass = s.getClass();
boolean serializable = false;
boolean externalizable = false;
while (!myClass.getName().equals("java.lang.Object")) {
Class[] interfaces = myClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].getName().equals(
"java.io.Serializable"))
serializable = true;
if (interfaces[i].getName().equals(
"java.io.Externalizable"))
externalizable = true;
}
}
myClass = myClass.getSuperclass();
if (serializable)
System.out.println(
"You are a serializable persistent bean");
if (externalizable)
System.out.println(
"You are an externalizable persistent bean");
System.exit(0);
}
} catch (Exception e) {
System.out.println("Exception: " + e);
}
}
- 299
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
11.
11.9
Reflection und Introspection nutzen
Introspection Szenarien
Regeln, um anpaßbare Beans zu
erstellen
• Halte die JavaBeans Namenskonventionen hundertprozentig ein.
Damit müssen keine BeanInfo Metadaten über die StandardEigenschaften, -Methoden und -Ereignisse zur Verfügung gestellt
werden.
• Erstelle eine BeanInfo Klasse mit speziellen Meta-Informationen,
z.B. über einen Icon und benutzerfreundliche Namen.
• Stelle Meta-Daten zur Verfügung, wenn der Introspector zu viele
und verwirrende Daten liefern würde, z.B. bei einer tiefen
Vererbungshierarchie.
• Verwende eine Manifest-Datei, um alle Klassen zur Design-Zeit zu
beschreiben. Ggf. erstelle eine JAR-Datei für das Design.
• Entwickle Beans, so daß sie angepaßt und mit Werkzeugen
bearbeitet werden können. Die Erstellung von BeanInfo Klassen,
Property Editoren, Customizers, Manifest-Dateien und JARs kostet
zusätzliche Aufwand.
- 300
© Prof. Dr. B. Dreher, FB Informatik
FH Wiesbaden – University of Applied Sciences
-
Spez. Methoden der Softwaretechnik: Software-Komponenten, SS 1999
Herunterladen