W poprzedniej sekcji dowiedzieliśmy się, w jaki sposób zmieniać zasoby metodą wsadową przy użyciu elementu wykonywalnego (Zmienianie zasobów metodą wsadową). Przyjrzyjmy się drugiej stronie medalu. Co zrobić, aby móc śledzić wszystkie zmiany zachodzące w obszarze roboczym w trakcie działania modułu dodatkowego? Można zarejestrować w obszarze roboczym obiekt IResourceChangeListener. Obiekt nasłuchiwania będzie powiadamiany o zmianach przez obiekt IResourceChangeEvent opisujący zmiany.
Najpierw należy zarejestrować w obszarze roboczym obiekt nasłuchiwania zmian w zasobach.
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener( listener, IResourceChangeEvent.POST_CHANGE);
Obiekt nasłuchiwania będzie powiadamiany o zmianach dokonanych w zasobach obszaru roboczego. Metody interfejsu API zasobów, które modyfikują zasoby, wyzwalają te zdarzenia jako część ich udokumentowanego zachowania. Komentarz dotyczący metody interfejsu API zasobu określa jednoznacznie czy zdarzenie zmiany zasobu ma zostać wyzwolone, czy nie. Na przykład tak, jak to ujęto w poniższym komentarzu do metody IFile.setContents():
Ta metoda zmienia zasoby; te zmiany są następnie zgłaszane w zdarzeniu zmiany zasobu, ze wskazaniem pliku, którego treść została zmieniona.
Te zdarzenia są zazwyczaj wyzwalane przez metody, które tworzą, usuwają lub zmieniają zasób. Metody, które czytają zasoby, ale ich nie zapisują, zazwyczaj nie wyzwalają tych zdarzeń.
Zdarzenie związane ze zmianą w zasobie opisuje specyfikę zmiany (lub zestawu zmian), które miały miejsce w obszarze roboczym. Zdarzenie zawiera deltę zasobu, która opisuje efekt netto dokonanych zmian. Jeśli na przykład w obrębie jednego zadania wsadowego zmian dany zasób zostanie dodany, a następnie usunięty, to ten zasób nie zostanie ujęty w delcie.
Delta zasobu ma postać drzewa strukturalnego zakorzenionego w katalogu głównym obszaru roboczego. Drzewo delty zasobu opisuje następujące typy zmian:
Aby poruszać się po drzewie delty zasobu, można zaimplementować interfejs IResourceDeltaVisitor lub można poruszać się po drzewie przy użyciu metody IResource.getAffectedChildren. Goście delty zasobu implementują metodę visit, która jest wywoływana przez deltę zasobu, ponieważ numeruje ona każdą zmianę w drzewie.
Uwaga: Zmiany dokonane we właściwościach sesji lub właściwościach trwałych nie są identyfikowane w delcie zasobu.
Zdarzenia związane ze zmianami w zasobach są wysyłane po każdej zmianie (lub wsadowym zestawie zmian) w obszarze roboczym. Ponadto są one wysyłane dla pewnych określonych operacji związanych z obszarem roboczym. Poniższa tabela zawiera krótki opis typów zdarzeń związanych ze zmianami w zasobach oraz momentów, w których są zgłaszane.
Typ zdarzenia |
Opis |
---|---|
PRE_CLOSE |
Powiadamia obiekt nasłuchiwania o planowanym zamknięciu projektu. To zdarzenie może służyć do wyodrębniania i zapisywania potrzebnych informacji dotyczących projektu znajdujących się w pamięci (na przykład właściwości sesji) przed jego zamknięciem. (Po zamknięciu projektu informacje znajdujące się w pamięci zostają usunięte). W trakcie tego zdarzenia obszar roboczy zostaje zablokowany i żadne zasoby nie mogą być aktualizowane. Zdarzenie zawiera projekt, który jest zamykany. |
PRE_DELETE |
Powiadamia obiekt nasłuchiwania o planowanym usunięciu projektu. To zdarzenie może być używane do przeprowadzania operacji czyszczenia, takich jak usuwanie zapisanych stanów dotyczących projektu z katalogu danego modułu dodatkowego. W trakcie tego zdarzenia obszar roboczy zostaje zablokowany i żadne zasoby nie mogą być aktualizowane. Zdarzenie zawiera projekt, który jest usuwany. |
PRE_AUTOBUILD |
Powiadamia obiekty nasłuchiwania przed rozpoczęciem automatycznego budowania. To zdarzenie jest rozgłaszane, gdy platforma wykryje konieczność automatycznego budowania, bez względu na to, czy automatyczne budowanie jest w danym momencie włączone. W trakcie tego zdarzenia obszar roboczy nie jest blokowany i zasoby mogą być aktualizowane. To zdarzenie zawiera deltę zasobu opisującą zmiany dokonane od czasu ostatniego zgłoszenia zdarzenia POST_CHANGE. |
POST_AUTOBUILD |
Powiadamia obiekty nasłuchiwania po zakończeniu automatycznego budowania. To zdarzenie jest rozgłaszane po przeprowadzeniu przez platformę operacji automatycznego budowania, bez względu na to, czy automatyczne budowanie jest w danym momencie włączone. W trakcie tego zdarzenia obszar roboczy nie jest blokowany i zasoby mogą być aktualizowane. To zdarzenie zawiera deltę zasobu opisującą zmiany dokonane od czasu ostatniego zgłoszenia zdarzenia POST_CHANGE. |
POST_CHANGE |
Opisuje zestaw zmian dokonanych w obszarze roboczym od czasu ostatniego zgłoszenia zdarzenia POST_CHANGE. Jest wyzwalane po każdym indywidualnym użyciu interfejsu API zmiany w zasobie, jak również po wsadowym zestawie zmian w obszarze roboczym. Jest wyzwalane również po zakończeniu każdego powiadomienia PRE_AUTOBUILD lub POST_AUTOBUILD. To zdarzenie zawiera deltę zasobu opisującą zmiany netto dokonane od czasu ostatniego zgłoszenia zdarzenia POST_CHANGE. W trakcie tego zdarzenia obszar roboczy zostaje zablokowany i żadne zasoby nie mogą być aktualizowane. |
Poniższy przykład implementuje obiekt nasłuchiwania zmian w zasobach oparty na konsoli. Obiekt nasłuchiwania zmian w zasobach jest rejestrowany dla konkretnych typów zdarzeń, a informacje o tych zdarzeniach są wyświetlane w konsoli:
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_AUTO_BUILD | IResourceChangeEvent.POST_AUTO_BUILD | IResourceChangeEvent.POST_CHANGE);
Obiekt nasłuchiwania sprawdza każdy typ zdarzenia i zgłasza informacje o zmienionych zasobach oraz rodzaje dokonanych zmian. Ten przykład został zaprojektowany, aby pokazać ogólny obiekt nasłuchiwania, który obsługuje wszystkie typy zdarzeń związanych z zasobami, jednak typowy obiekt nasłuchiwania rejestrowałby tylko jeden typ zdarzenia.
W implementacji zdarzenia POST_CHANGE stosowana jest dodatkowa klasa, która może zostać użyta do sprawdzenia zmian w delcie zasobu.
import org.eclipse.resources.*; import org.eclipse.runtime.*; public class MyResourceChangeReporter implements IResourceChangeListener { public void resourceChanged(IResourceChangeEvent event) { IResource res = event.getResource(); switch (event.getType()) { case IResourceChangeEvent.PRE_CLOSE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to close."); break; case IResourceChangeEvent.PRE_DELETE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to be deleted."); break; case IResourceChangeEvent.POST_CHANGE: System.out.println("Resources have changed."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.PRE_AUTO_BUILD: System.out.println("Auto build about to run."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.POST_AUTO_BUILD: System.out.println("Auto build complete."); event.getDelta().accept(new DeltaPrinter()); break; } } }
W celu sprawdzenia treści delty zasobu klasa DeltaPrinter implementuje interfejs IResourceDeltaVisitor. Metoda visit() jest wywoływana dla każdej zmiany zasobu w delcie zasobu. Gość używa wartości zwracanej do wskazania, czy powinny zostać sprawdzone delty zasobów potomnych.
class DeltaPrinter implements IResourceDeltaVisitor { public boolean visit(IResourceDelta delta) { IResource res = delta.getResource(); switch (delta.getKind()) { case IResourceDelta.ADDED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was added."); break; case IResourceDelta.REMOVED" System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was removed."); break; case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" has changed."); break; } return true; // odwiedź zasoby potomne } }
Z dostarczonej delty zasobu można uzyskać dodatkowe informacje. Poniższy fragment kodu pokazuje, w jaki sposób można zaimplementować przypadek IResourceDelta.CHANGED w celu uzyskania bardziej szczegółowego opisu zmian w zasobie.
... case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(delta.getFullPath()); System.out.println(" has changed."); int flags = delta.getFlags(); if ((flags & IResourceDelta.CONTENT) != 0) { System.out.println("--> Content Change"); } if ((flags & IResourceDelta.REPLACED) != 0) { System.out.println("--> Content Replaced"); } if ((flags & IResourceDelta.MARKERS) != 0) { System.out.println("--> Marker Change"); IMarkerDelta[] markers = delta.getMarkerDeltas(); // Aby uzyskać informacje na temat znaczników, należy sprawdzić te delty. } break; ...
Szczegółowy opis delt zasobów, gości i delt znaczników zawiera specyfikacja interfejsu API dla interfejsów IResourceDelta, IResourceDeltaVisitor oraz IMarkerDelta.
Uwaga: Obiekty nasłuchiwania zmian w zasobach pomagają śledzić zmiany dokonywane w zasobach, gdy moduł dodatkowy jest aktywny. Jeśli moduł dodatkowy rejestruje obiekty nasłuchiwania zmian w zasobach w swoim kodzie startowym, możliwe, że wiele zdarzeń związanych ze zmianami w zasobach zostanie wyzwolonych przed aktywowaniem modułu dodatkowego. Delta zasobu zawarta w pierwszym zdarzeniu związanym ze zmianą w zasobach otrzymanym przez moduł dodatkowy nie będzie zawierała wszystkich zmian dokonanych przed ostatnim aktywowaniem modułu dodatkowego. Jeśli konieczne jest śledzenie zmian między aktywacjami danego modułu dodatkowego, należy skorzystać z obsługi zapisywania obszaru roboczego. Ta czynność została opisana w sekcji Uczestnictwo w zapisywaniu obszaru roboczego.
Uwaga: Niektóre zdarzenia związane ze zmianami w zasobach są wyzwalane w procesach zachodzących w wątku działającym w tle. Obiekty nasłuchiwania zmian w zasobach powinny być wątkowo bezpieczne. Omówienie bezpieczeństwa wątków interfejsu użytkownika zawiera sekcja Zagadnienia związane z wątkami.