Henryk Budzisz ZPORR nr POKL.04.01.01-00-449/08-00 Koszalin 2009
Technologia JavaBeans Wprowadzenie Budowa komponentu Bean Zdarzenia Serializacja Podsumowanie nr POKL.04.01.01-00-449/08-00 2
Wprowadzenie Definicja komponentu Bean Cechy komponentu Bean Komponenty wizualne Środowiska programowe Przykład: pakiet ICEBrowser nr POKL.04.01.01-00-449/08-00 3
Definicja Bean jest obiektem, którego właściwości i funkcjonalność mogą być odczytywane i zmieniane zgodnie z określonym protokołem (JavaBean specification). Protokół ten określa zasady komunikacji pomiędzy Beanem, a otoczeniem (zwykle środowiskiem wizualnym). Definiując Bean definiujemy klasę, uwzględniając konwencje narzucone przez specyfikacje standardu. Nakład dodatkowej pracy na bycie komponentem Bean jest niewielki. nr POKL.04.01.01-00-449/08-00 4
Cechy komponentu Bean Komponenty Bean mają szereg cech wspólnych: Wsparcie dla introspekcji (ang. introspection) - udostępnianie informacji o właściwościach i obsługiwanych zdarzeniach. Wsparcie dla dostosowywania (ang. customization) ustawiania wyglądu i zachowania komponentu. Wsparcie dla obsługi zdarzeń (ang. events) komunikacji między komponentami Wsparcie dla utrwalania (ang. persistency) zapisywania i odczytywania informacji o stanie komponentu do/z pliku. nr POKL.04.01.01-00-449/08-00 5
Komponenty wizualne Większość komponentów Bean jest definiowana jako komponenty wizualne (zawierają metodę public void paint(graphics g) {... }). Takie komponenty wyprowadzane są z klasy java.awt.component (lub klas pochodnych), aby mogły być umieszczane w kontenerach. Klasy bibliotek AWT i Swing są komponentami Bean. Komponenty, które nie są wizualne (np. Timer lub ButtonGroup z biblioteki Swing), nie muszą być wyprowadzone z żadnej konkretnej klasy. nr POKL.04.01.01-00-449/08-00 6
Środowiska programowe Przykłady programowe zademonstrowane zostaną w dwóch środowiskach: RealJ bardzo proste środowisko tekstowe, dające pełną kontrolę nad tekstem źródłowym programu (środowisko niczego nie dopisuje ). NetBeans złożone środowisko graficzne dużo ułatwień, ale łatwo też stracić kontrolę nad tym co się dzieje w projekcie i w tekstach źródłowych. Popularnym środowiskiem graficznym jest Eclipse. nr POKL.04.01.01-00-449/08-00 7
Pakiet ICEBrowser Zestaw komponentów do budowania przeglądarki dokumentów HTML pochodzących z różnych żródeł (z połączenia HTTP, z anonimowego połączenia FTP, z lokalnego dyskowego systemu plikowego, z pliku spakowanego.jar, ze strumienia javowego Reader) Pakiet zrealizowany został w firmie ICEsoft Technologies, Inc. (www.icesoft.com). Wersja komercyjna jest bardziej rozbudowana i występuje w produktach wielu firm (Sun, Novell, Oracle,...). Komponenty zawarte są w pliku spakowanym icebrowserbean.jar. Dostępna jest również dokumentacja i przykłady użycia komponentów. nr POKL.04.01.01-00-449/08-00 8
Komponenty ICEBrowser Pakiet ice.htmlbrowser zawiera oprócz klas pomocniczych trzy komponenty: Document komponent interpretujący hipertekst i zarządzający dokumentami HTTP. Zbudowany na bazie klasy Panel biblioteki AWT. Browser komponent na bazie klasy Document, umożliwiający dostęp do hipertekstu pochodzącego z różnych źródeł, prowadzenie historii, itp. ICEBrowser gotowy aplet reprezentujący przeglądarkę dokumentów hipertekstowych. nr POKL.04.01.01-00-449/08-00 9
Komponent Document Dostępnych jest ok. 70 metod. Wybrane metody: gotolocation ustawia wskazany dokument w głównej ramce get-/setcurrentlocation pobiera/ustawia dokument w bieżącej ramce get-/setcurrentframe pobiera/ustawia bieżącą ramkę get-/setdocumenttitle pobiera/ustawia tytuł dokumentu getselectedtext pobiera zaznaczony tekst reload ponownie załadowuje dokument (odświeżanie) add-/removemouseoverlinklistener obsługa zdarzeń dot. linków add-/removepropertychangelistener obsługa zdarzeń dot. właściwości firepropertychange wygenerowanie zdarzenia dot. zmiany właściwości search wyszukuje podany tekst w dokumencie printdoc organizuje wydruk dokumentu HTML lub ramki nr POKL.04.01.01-00-449/08-00 10
Komponent Browser Browser dziedziczy metody komponentu Document, a ponadto zawiera 12 własnych metod. Wybrane metody: gotolocation załaduj dokument HTML goback wróć do poprzedniego dokumentu goforward wróć do dokumentu wcześniejszego getbackhistory zwróć historię odwiedzin getforwardhistory - zwróć historię odwiedzin get-/setcachesize podaj/ustaw rozmiar buforu dokumentów nr POKL.04.01.01-00-449/08-00 11
Zastosowania komponentów ICEBrowser do budowy systemu pomocy on-line dla aplikacji. dostęp do stron wwwz poziomu aplikacji. budowanie interfejsu dla aplikacji rozproszonych. Przykłady: Programy\RealJ\TestHTMLBrowser1 Programy\NetBeans\TestHTMLBrowser1 nr POKL.04.01.01-00-449/08-00 12
Budowa komponentu Bean Konstruktor bezparametrowy Właściwości i akcesory Właściwości proste Właściwości logiczne Właściwości indeksowane Właściwości związane i ograniczone Metody publiczne komponentu nr POKL.04.01.01-00-449/08-00 13
Konstruktor bezparametrowy Komponent JavaBeans musi zawierać konstruktor bezparametrowy, np.: void Button() {... } Umożliwia to dynamiczne ładowanie klasy i tworzenie obiektu przy użyciu metody Bean.instantiate(...) nr POKL.04.01.01-00-449/08-00 14
Właściwości i akcesory Właściwość (ang. property) jest definiowana poprzez nazwę funkcji nazywanej akcesorem (ang. accessor). Nazwa ta rozpoczyna się przedrostkiem get-, set- lub is-. Getter jest akcesorem służącym do pobierania wartości właściwości. Przykład: getlabel definiuje właściwość label (zmiana wielkości pierwszej litery) Setter służy do ustawiania właściwości, np.: setcolor definiuje właściwość color. Zmiana właściwości jest często uzgadniana z innymi komponentami. nr POKL.04.01.01-00-449/08-00 15
Właściwości proste Właściwość prosta ma pojedynczą wartość. Getter: <typ właściwości> get<nazwa właściwości> () { <definicja> } Setter: void set<nazwa właściwości> (<typ właściwości>) { <definicja> } Przykład definiowania właściwości prostej foreground: private Color color; // zmienna pomocnicza // definicja akcesorów public Color getforeground() // getter { return color; } public void setforeground(color c) // prosty setter { color = c; } nr POKL.04.01.01-00-449/08-00 16
Fragment kodu klasy AbstractButton.java (Sun Microsystems) /** * Returns the button's text. * @return the buttons text * @see #settext */ public String gettext() { return text; } /** * Sets the button's text. * @param text the string used to set the text * @see #gettext * @beaninfo * bound: true * preferred: true * attribute: visualupdate true * description: The button's text. */ public void settext(string text) { String oldvalue = this.text; this.text = text; firepropertychange(text_changed_property, oldvalue, text); updatedisplayedmnemonicindex(text, getmnemonic()); } if (accessiblecontext!= null) { accessiblecontext.firepropertychange( AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY, oldvalue, text); } if (text == null oldvalue == null!text.equals(oldvalue)) { revalidate(); repaint(); } nr POKL.04.01.01-00-449/08-00 17
Właściwości logiczne Właściwość logiczna jest właściwością prostą typu boolean, ale ma inne akcesory. Getter: boolean is<nazwa właściwości> () { <definicja> } Setter: void set<nazwa właściwości> (boolean) { <definicja> } Przykład: private boolean selected; // definicja akcesorów public boolean isselected() // getter { return selected; } public void setselected(boolean sel) // prosty setter { selected = sel; } nr POKL.04.01.01-00-449/08-00 18
Fragment kodu klasy AbstractButton.java (Sun Microsystems) /** * Returns the state of the button. True if the * toggle button is selected, false if it's not. * @return true if the toggle button is selected, otherwise false */ public boolean isselected() { return model.isselected(); } /** * Sets the state of the button. Note that this method does not * trigger an <code>actionevent</code>. * Call <code>doclick</code> to perform a programatic action change. * * @param b true if the button is selected, otherwise false */ public void setselected(boolean b) { boolean oldvalue = isselected(); model.setselected(b); } nr POKL.04.01.01-00-449/08-00 19
Właściwości indeksowane Właściwość indeksowana jest tablicą elementów. Getter elementu: <typ właściwości> get<nazwa właściwości> (int) { <definicja> } Setter elementu: void set<nazwa właściwości> (int, <typ właściwości>) { <definicja> } Getter tablicy: <typ właściwości>[] get<nazwa właściwości> () { <definicja> } Setter tablicy: void set<nazwa właściwości> (<typ właściwości>[]) { <definicja> } Przykład: void setwykaz (String[]) {... } nr POKL.04.01.01-00-449/08-00 20
Właściwości związane i ograniczone Właściwości komponentu mogą być związane (ang. bounded), tzn. o zmianie tej właściwości informowane są inne komponenty i reagują na tą zmianę. Właściwości komponentu mogą być ograniczane (ang. constrained), tzn. o zmianie powiadamiane są inne komponenty; zmiana dochodzi do skutku jeżeli żaden z powiadomionych komponentów nie zawetuje zmiany. Mechanizm ten funkcjonuje w oparciu o generowanie i rozsyłanie odpowiednich zdarzeń. nr POKL.04.01.01-00-449/08-00 21
Metody publiczne komponentu Metody publiczne komponentu są często wykorzystywane w trakcie komunikacji pomiędzy komponentami (są wywoływane w trakcie obsługi zdarzeń przychodzących z innych komponentów). Metody te powinny być synchronizowane dla zapewnienia poprawnej obsługi wywołań pochodzących z różnych wątków. nr POKL.04.01.01-00-449/08-00 22
Zdarzenia Koncepcja Hierarchia zdarzeń Tworzenie słuchacza Interfejsy nasłuchu Rejestracja słuchaczy Klasa narzędziowa PropertyChangeSupport Rozgłaszanie zmian właściwości Wetowanie zmian właściwości nr POKL.04.01.01-00-449/08-00 23
Koncepcja Źródło zdarzenie Słuchacz Programowa realizacja: Utworzyć obiekt Słuchacza (obiekt klasy implementującej interfejs nasłuchu lub klasy potomnej z adaptera). Przyłączyć obiekt słuchacza do jednego lub większej liczby komponentów. nr POKL.04.01.01-00-449/08-00 24
Hierarchia zdarzeo Object EventObject PropertyChangeEvent AWTEvent ActionEvent AdjustmentEvent ItemEvent TextEvent ComponentEvent ContainerEvent WindowEvent FocusEvent InputEvent KeyEvent MouseEvent nr POKL.04.01.01-00-449/08-00 25
Zdarzenie ActionEvent ActionEvent(Object source, int id, String command) gdzie: source - odniesienie na obiekt, który jest źródłem zdarzenia; słuchacz może użyć metody getsource aby pobrać to odniesienie. id identyfikator liczbowy (zwykle stała ACTION_PERFORMED); słuchacz może użyć metody getid command dowolny łańcuch, np. etykietka przycisku albo nazwa opcji menu; słuchacz może użyć metody getactioncommand Przykład generowania zdarzenia: ActionEvent action = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, label); Powiadamianie przyłączonego słuchacza o zdarzeniu action: listener.actionperformed(action); nr POKL.04.01.01-00-449/08-00 26
Zdarzenie MouseEvent public MouseEvent(Component source, int id, long when, int modifiers, int x, int y, int clickcount, boolean popuptrigger) Parametry: source odniesienie na żródło zdarzeń id identyfikator liczbowy (patrz: dokumentacja JDK) when czas powstania zdarzenia. modifiers modyfikator wskazujący na użycie klawisza modyfikującego (np.: shift, ctr, alt). x, y- współrzędne kursora myszki. clickcount liczba kliknięć myszki związanych ze zdarzeniem. popuptrigger zmienna logiczna; prawdziwa jeżeli zdarzenie wyzwala menu rozwijane. Parametry te są dostępne z poziomu słuchacza poprzez gettery. Przykład: Programy\RealJ\TestHTMLBrowser2.java klasa Nawigacja funkcja mousereleased nr POKL.04.01.01-00-449/08-00 27
Zdarzenie PropertyChangeEvent PropertyChangeEvent(Object source, String propertyname, Object oldvalue, Object newvalue) Parametry: source komponent JavaBean, który jest źródłem zdarzenia. propertyname nazwa właściwości, która została zmieniona. oldvalue poprzednia wartość właściwości. newvalue nowa wartość właściwości. Przykład generowania zdarzenia: PropertyChangeEvent propevt = new PropertyChangeEvent(this, text, oldtxt, newtxt); Jeżeli wartość właściwości jest typu prostego (np. int), musi być przekształcona w obiekt klasy opakowującej (dla int jest to Integer) nr POKL.04.01.01-00-449/08-00 28
Tworzenie słuchacza Słuchacz - to klasa, która może obsługiwać zdarzenie. Każda klasa, która implementuje interfejs nasłuchu staje się Słuchaczem, np.: public class MojaKlasa implements ActionListener {... } Każda klasa implementująca interfejs musi zdefiniować metody interfejsu. Dla interfejsu ActionListener jest to: public void actionperformed(actionevent e) { // instrukcje obsługujące zdarzenie } Klasa-słuchacz może też implementować większą liczbę interfejsów nasłuchu (określamy w ten sposób zestaw obsługiwanych zdarzeń). nr POKL.04.01.01-00-449/08-00 29
Interfejsy nasłuchu EventListener ActionListener Action WindowListener MouseListener MouseInputListener MouseMotionListener MenuListener PropertyChangeListener VetoableChangeListener nr POKL.04.01.01-00-449/08-00 30
Interfejsy nasłuchu zmian właściwości Interfejs PropertyChangeListener ma jedną metodę: public void propertychange(propertychangeevent e) Interfejs VetoableChangeListener również ma jedną metodę: public void vetoablechange(propertychangeevent e) throws PropertyVetoException Schemat definiowania słuchacza: public class Listener implements PropertyChangeListener {... public void propertychange(propertychangeevent e) {... } // propertychange... } Przykład: Programy\RealJ\TestHTMLBrowser4 nr POKL.04.01.01-00-449/08-00 31
Rejestracja słuchaczy (AWTEventMulticaster) Przykład użycia klasy bibliotecznej java.awt.awteventmulticaster do rejestrowania słuchaczy w komponencie AWT (JDK Help) public mycomponent extends Component { ActionListener actionlistener = null; public synchronized void addactionlistener(actionlistener l) { actionlistener = AWTEventMulticaster.add(actionListener, l); } public synchronized void removeactionlistener(actionlistener l){ actionlistener = AWTEventMulticaster.remove(actionListener, l); } public void processevent(awtevent e) { // when event occurs which causes "action" semantic ActionListener listener = actionlistener; if (listener!= null) { listener.actionperformed(new ActionEvent()); } } } nr POKL.04.01.01-00-449/08-00 32
Rejestracja słuchaczy w kontenerze // Utility field holding table of ActionListeners. // Generic type is used to declare this container. private Vector<ActionListener> listeners = new Vector<ActionListener>(); // Registers ActionListener to receive events. public synchronized void addactionlistener(actionlistener listener) { listeners.addelement(listener); } // Removes ActionListener from the list of listeners. public synchronized void removeactionlistener(actionlistener listener) { listeners.removeelement(listener); } // Notifies all registered listeners about the event. private void fireactionperformed(actionevent event) { Vector<ActionListener> targets; synchronized (this) { targets = (Vector<ActionListener>)listeners.clone(); } } for (ActionListener target : targets) target.actionperformed(event); Przykład : Programy\NetBeans\ Beans\OvalButton.java nr POKL.04.01.01-00-449/08-00 33
Klasa narzędziowa PropertyChangeSupport Wybrane metody klasy: public PropertyChangeSupport(Object sourcebean) // constructor public void addpropertychangelistener(propertychangelistener listener) public void removepropertychangelistener(propertychangelistener listener) public void firepropertychange(string propertyname, Object oldvalue, Object newvalue) public void firepropertychange(string propertyname, int oldvalue, int newvalue) public void firepropertychange(string propertyname, boolean oldvalue, boolean newvalue) public void firepropertychange(propertychangeevent evt) Dla właściwości ograniczonych stosuje się klasę VetoableChangeSupport. nr POKL.04.01.01-00-449/08-00 34
Rozgłaszanie zmian właściwości Setter, który zmienia właściwość związaną powinien powiadomić o tym wszystkich słuchaczy zmian właściwości (obiekty klas implementujących interfejs PropertyChangeListener) przyłączonych do komponentu, np.: private PropertyChangeSupport propertysupport = new PropertyChangeSupport(this);... public void seturl(string URL) { String oldurl = this.url; this.url = URL; propertysupport.firepropertychange("url", oldurl, URL); } nr POKL.04.01.01-00-449/08-00 35
Przykład: HyperlinkedLabel Demonstruje: Użycie klasy narzędziowej PropertyChangeSupport. Setter i getter właściwości hyperlinkcolor oraz URL. Zgłaszanie zmian właściwości hyperlinkcolor oraz URL. Implementację interfejsu MouseListener (jest słuchaczem zdarzeń MouseEvent). Sposób dodawania i usuwania słuchaczy akcji. Generowanie i rozsyłanie zdarzeń ActionEvent w odpowiedzi na kliknięcie myszki. Dorysowanie podkreślenia pod etykietką. nr POKL.04.01.01-00-449/08-00 36
Wetowanie zmian właściwości Setter, który zmienia właściwość ograniczoną powinien przed tą zmianą powiadomić wszystkich przyłączonych słuchaczy implementujących interfejs VetoableChangeListener, np.: public void setcount(int newcount) throws PropertyVetoException { int oldcount = count; // count - wartość właściwości vetoablechangesupport.firevetoablechange("count",oldcount,newcount); count = newcount; // przy braku wyjątku dochodzi do zmiany } Słuchacze mogą z przesłanego zdarzenia typu PropertyChangeEvent, odczytać (getnewvalue) proponowaną nową wartość. Jeżeli proponowana nowa wartość nie może być zaakceptowana, zgłaszany jest wyjątek PropertyVetoException. Zgłoszenie wyjątku przerywa wykonywanie dalszych instrukcji (do zmiany właściwości nie dochodzi) i następuje przejście do obsługi wyjątku. nr POKL.04.01.01-00-449/08-00 37
Przykład: Counter komponent JavaBeans klasa słuchacza wyjątek (exception) sterowanie wetowanie decbutton (JButton) addactionlistener addvetoablechangelistener limitator (Limitator) anonymous (ActionListener) decrement PropertyVetoExceprion addactionlistener anonymous (ActionListener) setcount counter (Counter) setcounter (JTextField) increment ostrzeganie addpropertychangelistener anonymous (ActionListener) proplistener (PropertyChangeListener) settext counterwarning (JLabel) incbutton (JButton) addactionlistener nr POKL.04.01.01-00-449/08-00 38
Serializacja Wprowadzenie Serializacja do pliku binarnego Deserializacja z pliku binarnego Serializacja i deserializacja XML nr POKL.04.01.01-00-449/08-00
Wprowadzenie Serializacja komponentu oznacza zapisanie jego stanu, tzn. ustawionych (np.: przez setter, konstruktor lub inną funkcję) wartości pól w tym również pól odziedziczonych. Serializowane są również obiekty utworzone wewnątrz komponentu, np.: ustawienia czcionki lub koloru. Deserializacja komponentu oznacza odtworzenie komponentu w takim stanie w jakim był przed serializacją. Klasy obiektów serializowanych muszą implementować interfejs Serializable. Interfejs ten nie zawiera żadnych metod. Składowe klasy, których nie chcemy serializować (hasła, zmienne pomocnicze itp.) oznaczamy słowem kluczowym transient. Nie są też serializowane pola statyczne (nie należą do obiektu). nr POKL.04.01.01-00-449/08-00
Serializacja komponentów Serializację obiektu, czyli zapis stanu obiektu w pliku dyskowym realizuje metoda writeobject() z klasy ObjectOutputStream. Jest to klasa opakowująca dowolny strumień zdefiniowany przez klasę wyprowadzoną z klasy abstrakcyjnej OutputStream. Przykład: JButton przycisk = new JButton( Pomoc ); // serializacja obiektu przycisk ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream( przycisk.ser )); out.writeobject(przycisk); // pominięto wyjątki nr POKL.04.01.01-00-449/08-00 41
Deserializacja komponentów Deserializacja obiektu, czyli odczytanie stanu obiektu wcześniej zserializowanego realizuje metoda readobject() z klasy ObjectInputStream. Jest to klasa opakowująca dowolny strumień zdefiniowany przez klasę wyprowadzoną z klasy abstrakcyjnej InputStream. Przykład: ObjectInputStream in = new ObjectInputStream( new FileInputStream( przycisk.ser )); // deserializacja obiektu przycisk JButton przycisk = (JButton)in.readObject(); Przykład programowy: Programy\RealJ\Serializacja.java i Programy\RealJ\Deserializacja.java. nr POKL.04.01.01-00-449/08-00 42
Serializacja do dokumentu XML Możliwa jest również serializacja przez utworzenie dokumentu tekstowego XML. Klasy ObjectOutputStream i ObjectInputStream zastępuje się odpowiednio przez klasy XMLEncoder i XMLDecoder zdefiniowane w pakiecie java.beans. Klasy te mają takie same metody odczytu i zapisu: readobject() i writeobject(). Przykład: Programy\RealJ\SerializacjaXML.java i Programy\RealJ\DeserializacjaXML.java nr POKL.04.01.01-00-449/08-00 43
Podsumowanie Zasady definiowania komponentu JavaBeans: Klasę definiującą komponent należy zdefiniować jako serializowaną. Należy zdefiniować konstruktor bezparametrowy. Właściwości komponentu są zdefiniowane przez zestaw setterów i getterów (również odziedziczonych). Zdarzenia obsługiwane przez komponent określone są przez parę metod addxxxlistener/removexxxlistener (gdzie: XXX jest nazwą zdarzenia) zdefiniowanych w komponencie (lub odziedziczonych). Metody publiczne komponentu powinny być synchronizowane. nr POKL.04.01.01-00-449/08-00 44