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