Programowanie komponentowe Henryk Budzisz
wersja 1.0
Koszalin 2006 Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
Program wykładów
Wprowadzenie Technologia JavaBeans Technologia CORBA Technologie COM/DCOM/COM+ Technologia .NET Technologia XML Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
2
Wprowadzenie
Koncepcje Komponent programowy Technologie
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
3
„Klejenie” aplikacji Programowanie komponentowe (PK) jest procesem tworzenie aplikacji (systemu informatycznego) poprzez „sklejanie” jej z gotowych, odpowiednio przygotowanych, wymiennych komponentów programowych. Budowanie aplikacji z komponentów jest często porównywane do budowania (żargonowo klejenia) układu (urządzenia) elektronicznego z gotowych, seryjnych komponentów elektronicznych (scalaków, tranzystorów, przełączników). Zarówno w jednym jak i w drugim przypadku, komponenty muszą być przystosowane do tego „klejenia” (wykonane według określonych standardów). Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
4
Zastępowalność Podstawowym celem praktycznym PK, jest stworzenie warunków do łatwej zastępowalności komponentów. Systemy informatyczne podlegają ciągłym zmianom. Jest to proces kosztowny i często naruszający niezawodność oprogramowania. Możliwość zastąpienia komponentu przez jego nową wersję lub zupełnie inną implementację, bez potrzeby rozmontowywania całego systemu, jest niezwykle atrakcyjna z praktycznego punktu widzenia. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
5
Programowanie komponentowe a programowanie obiektowe Komponent musi odpowiadać specyfikacjom określonym dla danej technologii. Sposób implementacji komponentu nie jest narzucany. Ponieważ idee programowania komponentowego i programowania obiektowego w dużym stopniu pokrywają się, komponenty są zwykle definiowane poprzez klasy. Klasy definiujące komponenty muszą spełniać wymagania określone w specyfikacji, np. zapewnić serializację, mechanizmy łączenia i komunikacji, samoinstalację itp. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
6
Komponent programowy Komponent jest wyizolowaną (autonomiczną) jednostką programową, która zgodnie z przyjętymi standardami: zawiera dane i metody realizujące operacje na tych danych – niezależnie od otoczenia (hermetyzacja) udostępnia zestaw oferowanych usług poprzez interfejs programowy. zapewnia komunikację z innymi komponentami. zapewnia „utrwalanie” i odtwarzanie stanu wewnętrznego. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
7
Technologie JavaBeans – wprowadzona do języka Java już od pierwszej wersji. CORBA (ang. Common Object Request Broker Architecture ) COM (ang. Component Object Model) – opracowana przez Microsoft; następnie rozszerzona do DCOM i COM+ .NET – lansowana przez Microsoft jako następca COM/DCOM/COM+ XML – nowy zawodnik w grze komponentowej
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
8
Technologie sieciowe Wraz z rozwojem programowania sieciowego i rozproszonego wspomniane technologie zostały zostały rozszerzone: EJB – Enterprice Java Beans firmy Sun CCM – CORBA Component Model DCOM/COM+ - rozszerzenie technologii COM
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
9
„Mój klej jest lepszy od twojego kleju” Jaką technologię „klejenia” wybrać? Patrząc z odległości 1000 m, efekt „klejenia” w każdej technologii jest podobny. Podstawowe koncepcje są wspólne. Z bliska jednak dostrzegamy, że w każdej technologii stosuje się zdecydowanie różne techniki i style programowania dla osiągnięcia celu. Każda technologia komponentowa ma swoich zwolenników. Na razie nie widać przegranych.
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
10
Technologia JavaBeans
Wprowadzenie Budowa komponentu Bean Zdarzenia Refleksja i introspekcja Serializacja Podsumowanie
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
11
Wprowadzenie
Definicja komponentu Bean Cechy komponentu Bean Komponenty wizualne Środowiska programowe Przykład: pakiet ICEBrowser
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
12
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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
13
Cechy komponentu Bean Komponenty Bean mają wspólne cechy:
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.
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
14
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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
15
Ś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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
16
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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
17
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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
18
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
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
19
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
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
20
Zastosowania komponentów ICEBrowser
do budowy systemu pomocy on-line dla aplikacji.
dostęp do stron www z poziomu aplikacji.
budowanie interfejsu dla aplikacji rozproszonych.
Przykłady:
HTMLBrowser\demo1 (RealJ) HTMLBrowser\TestHTMLBrowser1 (NetBeans)
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
21
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
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
22
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(...)
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
23
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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
24
Właściwości proste Właściwość prosta ma pojedynczą wartość. Getter:
get () { }
Setter:
void set () { }
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; }
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
25
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(); } Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
26
Właściwości logiczne Właściwość logiczna jest właściwością prostą typu boolean, ale ma inne akcesory. Getter:
boolean is () { }
Setter:
void set (boolean) { }
Przykład:
private boolean selected; // definicja akcesorów public boolean isSelected() { return selected; } public void setSelected(boolean sel) { selected = sel; }
Wprowadzenie Beans COM NET XML CORBA
// getter // prosty setter
© H.Budzisz
27
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 actionEvent. * Call doClick 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); } Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
28
Właściwości indeksowane Właściwość indeksowana jest tablicą elementów. Getter elementu:
get (int) { }
Setter elementu:
void set (int, ) { }
Getter tablicy:
[] get () { }
Setter tablicy:
void set ([]) { }
Przykład: void setWykaz (String[]) { ... } Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
29
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ń.
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
30
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.
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
31
Zdarzenia
Koncepcja Hierarchia zdarzeń Tworzenie słuchacza Przyłączanie słuchacza Adaptery Anonimowe klasy wewnętrzne Klasa narzędziowa PropertyChangeSupport Rozgłaszanie zmian właściwości Wetowanie zmian właściwości Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
32
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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
33
Hierarchia zdarzeń Object EventObject
PropertyChangeEvent
AWTEvent ActionEvent AdjustmentEvent
ContainerEvent
ItemEvent
WindowEvent
TextEvent
FocusEvent
ComponentEvent
InputEvent
KeyEvent MouseEvent Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
34
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); Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
35
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: demo2.java klasa Nawigacja funkcja mouseReleased (RealJ) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
36
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) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
37
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ń). Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
38
Interfejsy nasłuchu EventListener ActionListener
Action
WindowListener
MouseListener
MouseInputListener
MouseMotionListener MenuListener PropertyChangeListener VetoableChangeListener
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
39
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: demo6.java (RealJ) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
40
Przyłączanie słuchacza Wszystkie komponenty JavaBeans powinny umożliwiać przyłączanie/odłączanie określonych typów Słuchaczy. Służą do tego metody: addXXXListener() oraz removeXXXListener(), gdzie XXX jest typem słuchacza. Np.: zdarzenie ActionEvent może być obsłużone przez Słuchacza implementującego interfejs ActionListener; Słuchacz taki może być przyłączony do komponentów, które mają dostęp do metody addActionListener(). Są to: Button, List, TextField, MenuItem oraz klasy pochodne. Przykład: Słuchacz słuchacz = new Słuchacz(); przyciskOK.addActionListener(słuchacz);
Przykład programowy – Demo2.java (RealJ) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
41
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()); } } } Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
42
Rejestracja słuchaczy w kontenerze // Utility field holding table of ActionListeners. // Generic type is used to declare this container. private Vector listeners = new Vector(); // 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 targets; synchronized (this) { targets = (Vector)listeners.clone(); } Przykład (NetBeans) : for (ActionListener target : targets) target.actionPerformed(event); OvalButton.java } Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
43
Adaptery Implementację interfejsu można wykonać w pomocniczej klasie zwanej adapterem, a następnie zdefiniować klasę słuchacza jako rozszerzenie adaptera, np.: class WindowAdapter implements WindowListener { public void windowActivated(WindowEvent e) {} public void windowClosed(WindowEvent e) {} // następne metody }
class Słuchacz extends WindowAdapter { // definicja potrzebnej metody }
Pakiet java.awt.event zawiera takie adaptery.
Przykład: Demo3.java (RealJ) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
44
Anonimowe klasy wewnętrzne Klasa wewnętrzna jest definiowana wewnątrz innej klasy, np.: class KlasaZewnętrzna { class KlasaWewnętrzna { ... } ... }
Klasa wewnętrzna może być zdefiniowana nawet wewnątrz funkcji. Klasa anonimowa, to klasa bez nazwy, definiowana w momencie tworzenia obiektu (tj. przy użyciu operatora new). Przykłady: Demo4.java, Demo5.java (RealJ) i TestHTMLBrowser2 (NetBeans) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
45
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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
46
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); } Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
47
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ą.
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
48
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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
49
Przykład: Counter sterowanie decButton
addActionListener
komponent
klasa
wyjątek
JavaBeans
słuchacza
(exception)
wetowanie addVetoableChangeListener
(JButton)
limitator (Limitator)
anonymous (ActionListener) decreace
addActionListener
anonymous
setText
(ActionListener)
PropertyVetoExceprion
counter (Counter)
setCounter
ostrzeganie
(JTextField) increace
addPropertyChangeListener anonymous (ActionListener)
setText
propListener
counterWarning
(PropertyChangeListener) incButton
(JLabel)
addActionListener
(JButton)
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
50
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.
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
51
Refleksja i introspekcja
Automatyzacja tworzenia i dostosowywania komponentu Klasa Class Dynamiczne ładowanie klas Dynamiczne pobieranie metody Dynamiczne wywołanie metody Introspekcja Narzędzia graficzne
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
52
Automatyzacja tworzenia i dostosowywania komponentu Przeciągnięcie ikony komponentu z palety na obszar projektowanego interfejsu graficznego powoduje utworzenie obiektu tej klasy. Przy użyciu mechanizmu refleksji rozpoznaje się typ komponentu, a następnie stosując konstruktor bezparametrowy, tworzy się obiekt. Następnie, stosując introspekcję należy z komponentu „wydobyć” informacje o właściwościach, setterach, getterach, obsługiwanych zdarzeniach i dostępnych metodach publicznych (bez dostępu do kodu źródłowego). W końcu, przy użyciu mechanizmu refleksji, należy udostępnić wartości właściwości (z możliwością edycji) oraz przyłączyć stosownych słuchaczy. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
53
Klasa Class W trakcie wykonywania instrukcji: Button anuluj = new Button(”Anuluj”);
potrzebna jest definicja klasy java.awt.Button. JVM odszukuje plik Button.class, dekoduje binarny format klasy, sprawdza kompatybilność z innymi klasami, weryfikuje sekwencję operacji kodu bajtowego, ładuje do pamięci i tworzy obiekt klasy Class zawierający metadane udostępniające informacje o modyfikatorach, konstruktorach, metodach i polach klasy Button. Dostęp do tego obiektu jest możliwy przez użycie metody getClass z klasy Object lub dodanie literału .class do nazwy klasy. Przykłady: Class c = anuluj.getClass(); Class c = java.awt.Button.class;
Przykład programowy: Introspekcja\ClassViewer.java (RealJ) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
54
Dynamiczne ładowanie klas Jeżeli w trakcie realizacji programu potrzebny jest obiekt pewnej klasy, można ją odszukać i załadować przy użyciu metody forName z klasy Class, np.: Class c = null; try { c = Class.forName(”beans.Counter”); } catch (ClassNotFoundException ex) { // obsługa wyjątku }
Obiekt załadowanej klasy można stworzyć przy użyciu metody newInstance z klasy Class, np.: Object object = = null; Objekt objekt new c(); try { object = c.newInstance(); } catch ... Wprowadzenie Beans COM NET XML CORBA
Nie można użyć operatora new © H.Budzisz
55
Dynamiczne pobieranie metody W załadowanej klasie, dostępnej przez obiekt klasy Class (w przykładzie beanClass) występują pola i metody. Dostęp do zdefiniowanej metody uzyskuje się przez podanie jej nazwy i parametrów jako argumentów metody getMethod z klasy Class. // tablica parametrów odpowiadających argumentom metody Class[] parameterTypes = new Class[] {String.class}; Method addTxt = null; try { addTxt = beanClass.getMethod("addText", parameterTypes); } catch (NoSuchMethodException ex) { ...}
Definicja metody jest reprezentowana przez obiekt klasy Method. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
56
Dynamiczne wywoływanie metody beanObject.addTxt(”Anuluj”);
Metodę reprezentowaną przez obiekt klasy Method (w przykładzie addTxt) wywołuje się stosując metodę invoke. Argumentami jej są: obiekt na rzecz którego jest wywoływana i argumenty wywołania. Object[] arguments = ”Anuluj”; try { addTxt.invoke(beanObject, arguments); } catch (IllegalArgumentException ex) { ... } catch (InvocationTargetException ex) { ... } catch (IllegalAccessException ex) { ... }
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
57
Podsumowanie W mechanizmie refleksji wykorzystuje się następujące klasy: java.lang.Class – reprezentuje klasę lub interfejs. java.lang.Object – udostępnia metodę getClass. java.lang.reflect.Constructor – udostępnia konstruktor klasy. Umożliwia dynamiczne tworzenie obiektu klasy. java.lang.reflect.Method – udostępnia metodę klasy. Umożliwia wywołanie metody. java.lang.reflect.Field – udostępnia pole klasy i dynamiczny dostęp do tego pola. java.lang.reflect.Modifier – udostępnia informacje o modyfikatorach definicji klasy (abstract, public, final). java.lang.reflect.Array – umożliwia dynamiczne deklarowanie tablic.
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
58
Introspekcja Dynamicznie załadowany Bean musi zostać „przebadany”. Służy do tego klasa Introspector, umieszczając wynik „badania” w obiekcie klasy BeanInfo. Służy do tego metoda: getBeanInfo(Class beanClass, Class stopClass)
Następuje odczytanie informacji o właściwościach, metodach i zdarzeniach w podanej klasie beanClass oraz wszystkich klasach bazowych, aż do klasy stopClass (ale bez niej). Przykład: BeanInfo bi = null; try { bi = Introspector.getBeanInfo(bean, Object.class); } catch(IntrospectionException e) { // obsługa wyjątku }
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
59
Wynik introspekcji Informacje o właściwościach, getterach, setterach, zdarzeniach i metodach umieszczone są w obiektach odpowiednich klas (rysunek), zdefiniowanych w pakiecie java.beans. PropertyDescriptor[] descriptors = bi.getPropertyDescriptors(); for(PropertyDescriptor d: descriptors) // extended for print("Nazwa właściwości:\n " + d.getName()); // inne metody klasy PropertyDescriptor // getPropertType, getReadMethod, getWriteMethod, ...
Przykład: BeanDumper.java (RealJ) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
60
Sterowanie introspekcją Realizuje się przez zdefiniowanie klasy o nazwie: BeanInfo, np.: JugglerBeanInfo implementującej interfejs BeanInfo. Ponieważ interfejs wymusza implementację ośmiu metod, wygodniejsze jest rozszerzenie pomocniczej klasy SimpleBeanInfo, np.: public class JugglerBeanInfo extends SimpleBeanInfo { }
W klasie tej definiuje się metody wykorzystywane podczas introspekcji: BeanDescriptor getBeanDescriptor() PropertyDescriptor[] getPropertyDescriptors(); MethodDescriptor[] getMethodDescriptors(); EventSetDescriptor[] getEventSetDescriptors();
Definiując metodę getIcon, można przypisać do komponentu ikonę. Przykład: JugglerBeanInfo.java (NetBeans) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
61
Narzędzia graficzne W środowisku graficznym nazwy komponentów są zastąpione przez ikony. Przeciągnięcie ikony z palety do obszaru projektowego powoduje utworzenie obiektu z użyciem konstruktora bezparametrowego. Poprzez introspekcję „odczytane” zostają właściwości komponentu oraz obsługiwane zdarzenia. Nazwy właściwości tworzą pierwszą kolumnę tabeli edycyjnej. Wartości właściwości są odczytywane przez gettery i tworzą drugą kolumnę tabeli edycyjnej. Do edycji właściwości używane są wyspecjalizowane edytory (koloru, czcionki, łańcuchów itp.). Nowe wartości są ustawiane w komponencie przez settery. W podobny sposób wiąże się zdarzenia z funkcjami odpowiedzi. Przykład: PropertyViewer.java (NetBeans) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
62
Serializacja komponentów Serializacja 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
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. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
63
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: Serializacja.java i Deserializacja.java (RealJ). Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
64
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: SerializacjaXML.java i DeserializacjaXML.java (RealJ) Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
65
Podsumowanie technologii JavaBeans
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
66
Technologia COM COM – Interfejsy Technologia COM w Visual C++ Globally Unique Identifiers (GUIDs) Biblioteka COM Tworzenie obiektu COM Inteface IUnknown Definiowanie komponentu
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
67
COM – co to jest? COM (Component Object Model) jest opracowaną przez Microsoft technologią umożliwiającą efektywną komunikację między aplikacjami Component Object Model definiuje: binarny standard wywoływania funkcji między komponentami, struktury interfejsów udostępnianych przez poszczególne obiekty, mechanizmy jednoznacznej identyfikacji komponentów i ich interfejsów.
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
68
Klient
Diagram binarnego standard wywoływania funkcji
Obiekt komponentowy (instancja komponentu)
wskaźnik na VTBL (pole prywatne)
VTBL jest wspólna dla wszystkich klientów korzystających z danego komponentu COM Serwer
wskaźnik na funkcję1 wskaźnik na funkcję2 wskaźnik na funkcję3 VTBL (tablica funkcji wirtualnych)
funkcja1(pObj,arg1,arg2,...) { ... } Implementacja komponentu COM zawarta zwykle w bibliotece DLL
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
69
Komponenty COM w jednym procesie
Technologia COM definiuje sposób współpracy pomiędzy komponentem a jego klientem. W pojedynczym procesie, klient łączy się z komponentem bez pośrednich komponentów. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
70
Komponenty COM w różnych procesach
Klient, który chce się skomunikować z komponentem musi skorzystać z pośrednictwa tzw. RPC stubs oraz obiektów Proxy, istniejących po obu stronach połączenia. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
71
Komponenty COM na różnych komputerach
Jeżeli klient i komponent rezydują na różnych komputerach, w technologii DCOM (Distributed COM) komunikację międzyprocesorową zastępuje się protokołem sieciowym. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
72
COM – Interfejsy Obiekty COM udostępniają swoje funkcje obiektom zewnętrznym za pośrednictwem interfejsów. Interfejs jest zestawem prototypów funkcji składowych komponentu COM (metod). Nazwy interfejsów przyjęło się poprzedzać przedrostkiem I, np.: ILookup Interfejs można zdefiniować na bazie innego interfejsu, czyli zastosować dziedziczenie (ale wyłącznie jednobazowe) Interfejs nie posiada własnej implementacji. Każdy komponent może implementować wiele interfejsów oferować wiele zestawów usług. Klienty (aplikacje lub inne komponenty) odwołują się do interfejsów za pośrednictwem wskaźników. Każdy interfejs posiada własny, unikalny identyfikator - Globally Unique Identifier (GUID). Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
73
Schemat implementacji interfejsu
Interfejsy
Każdy komponent może implementować wiele interfejsów oferować wiele zestawów usług. IA
IB
Komponent COM (coclass)
IC Komponent lub coclass (skrót od component object class) zawiera kod wszystkich funkcji udostępnianych przez interfejsy, funkcje pomocnicze i dane. Komponent jest umieszczony w serwerze COM - pliku binarnym (DLL lub EXE). Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
74
Implementacja interfejsu Implementacja interfejsu (definicja komponentu) może być zrealizowana w różnych językach programowania. Komponenty mogą być używane przez inne komponenty lub aplikacje realizowane w różnych językach programowania. Technologia COM definiuje standardy komunikowania się na poziomie binarnym. Na poziomie źródłowym ta sama funkcja będzie kodowana zgodnie ze składnią danego języka, np.: Visual Basic object.Add( Time As Double, Name As String ) As Variant C++ HRESULT Add( double Time, BSTR Name, VARIANT* pVal ); Java public com.ms.com.Variant Add( double Time, String Name );
Trzeba ponadto zapewnić konwersję typów danych. Szczegóły w dokumentacji MSDN (COM Language Translation). Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
75
Technologia COM w Visual C++ Preferowanym językiem implementacji jest C++. Interfejs jest definiowany jako klasa abstrakcyjna z czystymi funkcjami wirtualnymi. Do tworzonych obiektów automatycznie dołączana jest Vtable (tablica wywołań funkcji wirtualnych). W C trzeba taką tablicę samemu zdefiniować. Każda metoda musi mieć wskaźnik zwrotny na obiekt. W C++ automatycznie dodawany jest wskaźnik this. W C trzeba dodać do każdej funkcji dodatkowy parametr. Definicja klasy stanowi też automatycznie przestrzeń nazw dla składowych.
Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
76
Globally Unique Identifiers (GUIDs) Do identyfikacji każdego interfejsu i każdego komponentu, używany jest unikalny identyfikator (128-bitowa struktura; long + uint + uint + 8*char = 16 bajtów). Plik guiddef.h zawiera definicję struktury opisującej GUID i pomocnicze makrodefinicje, np.: DEFINE_GUID. Programista – zamiast tego identyfikatora – używa związanej z nim stałej symbolicznej IID_ lub CLSID_ . Przykład definicji stałej IID_ILOOKUP: DEFINE_GUID(IID_ILOOKUP, 0xc4910d71, 0xba7d, 0x11cd, 0x94, 0xe8, 0x08, 0x00, 0x17, 0x01, 0xa8, 0xa3);
Do generowania GUID udostępnione są programy narzędziowe (w Visual C++ Tools/Create GUID) oraz funkcja CoCreateGuid z COM API. Wprowadzenie Beans COM NET XML CORBA
© H.Budzisz
77
Obsługa błędów Wszystkie funkcje COM w Visual C++ (z wyjątkiem AddRef i Release z interfejsu IUnknown) zwracają jako wynik wartość typu HRESULT zawierającą informacje o błędach (plik winerror.h wiersz 17 040). Typowy schemat obsługi błędów: HRESULT hr; hr = funkcja_COM(parametry); if (hr == S_OK) { // dalsze operacje ... } else cerr