Zmiany wymagane w przypadku adaptowania mechanizmów i interfejsów API z wersji 3.0

W tej sekcji opisano zmiany wymagane do zmodyfikowania modułu dodatkowego z wersji 2.1 w celu zaadaptowania mechanizmów i interfejsów API z wersji 3.0.

Rezygnacja z modułu org.eclipse.core.runtime.compatibility

Środowisko wykonawcze platformy Eclipse 3.0 zostało znacząco zmodyfikowane. Implementacja bazowa opiera się na specyfikacji środowiska OSGi. Środowisko wykonawcze platformy Eclipse 3.0 zawiera warstwę kompatybilności (w module dodatkowym org.eclipse.core.runtime.compatibility), w której przechowuje się interfejsy API z wersji 2.1. Programiści tworzący moduły dodatkowe zainteresowani możliwością uzyskania dodatkowej wydajności i funkcjonalności powinni wziąć pod uwagę zaadaptowanie interfejsów API z wersji 3.0 i wyeliminowanie zależności od warstwy kompatybilności. Kod kompatybilności pojawia się w trzech miejscach:

W kolejnych sekcjach wyjaśniono bardziej szczegółowo, które klasy i metody są obecne w celu zachowania kompatybilności, a także przedstawiono instrukcje umożliwiające aktualizację modułów dodatkowych.

Moduły dodatkowe i pakunki

Środowisko wykonawcze platformy Eclipse zostało poddane refaktoryzacji w celu podziału na dwie części - zarządzanie wymaganiami wstępnymi i ładowaniem klas oraz zarządzanie rozszerzeniami/punktami rozszerzeń. Podział ten umożliwia naturalną, elastyczną adaptacje specyfikacji środowiska OSGi w celu zarządzania ładowaniem klas i wymaganiami wstępnymi. To pozwala z kolei korzystać z zestawu nowych możliwości środowiska wykonawczego, od dynamicznego instalowania/aktualizowania/deinstalowania modułów dodatkowych do zabezpieczeń i poszerzonych możliwości konfiguracyjnych.

Choć w dalszym ciągu pozostaje w użyciu określenie moduł dodatkowy, w nowym środowisku wykonawczym moduł dodatkowy to w istocie pakunek uzupełniony o dodatkowe rozszerzenia i punkty rozszerzeń. Termin pakunek jest zdefiniowany w specyfikacji środowiska OSGi i oznacza kolekcję typów i zasobów oraz powiązanych informacji o międzypakunkowych wymaganiach wstępnych. Rejestr rozszerzeń stanowi nową formę rejestru modułów dodatkowych i wyszczególnia jedynie informacje dotyczące rozszerzeń i punktów rozszerzeń. Interfejs API rejestru rozszerzeń w dużym stopniu pokrywa się z interfejsem API odpowiadającego mu rejestru modułów dodatkowych (więcej informacji na ten temat można znaleźć w sekcji Rejestry).

W środowisku wykonawczym platformy Eclipse 2.x obiekt modułu dodatkowego ma kilka ról i zadań:

W środowisku wykonawczym platformy Eclipse 3.0 te role i zadania są realizowane w ramach oddzielnych obiektów.

Bundle
Pakunki to jednostki modułowości przewidziane przez specyfikację OSGi. Na każdy pakunek przypada jeden program ładujący klasy. Istnieje możliwość konstruowania wykresów zależności ładowania klas między pakunkami typowych dla środowiska Eclipse. Pakunki mają cykl życia określający ich uruchomienie i zatrzymanie, a środowisko OSGi umożliwia rozgłaszanie zdarzeń związanych z pakunkami (np. instalowanie, rozwiązywanie, uruchamianie, zatrzymywanie czy deinstalowanie) w celu powiadomienia zainteresowanych stron. W przeciwieństwie do klasy Plugin ze środowiska Eclipse, klasa Bundle w środowisku OSGi nie jest rozszerzalna. Oznacza to, że programiści nie mają możliwości definiowania własnych klas pakunków.
BundleActivator
BundleActivator to interfejs definiowany przez środowisko OSGi. Każdy pakunek może definiować klasę aktywatora pakunku, podobnie jak każdy moduł dodatkowy może definiować własną klasę Plugin. Instancja określonej klasy jest tworzona przez środowisko i używana do implementowania przetwarzania cyklu życia z metodami start() i stop(). Istnieje jednak znacząca różnica w charakterze tego procesu. W środowisku Eclipse często stosowana (choć niezalecana) praktyka to użycie klas Plugin do inicjowania i rejestracji. W środowisku OSGi aktywatory mogą wyłącznie wykonywać rejestrację. Duża liczba wykonywanych operacji inicjowania (lub innych zadań) w metodzie BundleActivator.start() stanowi zagrożenie dla aktywności systemu.
BundleContext
Klasy BundleContext składają się na mechanizm środowiska OSGi służący do prezentowania poszczególnym pakunkom ogólnych funkcji systemowych. Każdy pakunek ma unikalną i prywatną instancję klasy BundleContext, którą wykorzystuje w celu uzyskiwania dostępu do funkcji systemowych, np. funkcji getBundles() w celu wykrycia wszystkich pakunków w systemie.
Plugin
Nowa klasa Plugin jest pod wieloma względami podobna do pierwotnej klasy Plugin ze środowiska Eclipse, z tym że obiekty Plugin nie są już wymagane ani zarządzane przez środowisko wykonawcze, a wiele metod straciło aktualność. Klasa ta ma zasadniczo charakter udogodnienia - udostępnia wiele użytecznych funkcji i mechanizmów, ale nie jest już bezwzględnie konieczna. Wiele z tych funkcji jest też dostępnych w klasie Platform środowiska wykonawczego.

Klasa Plugin implementuje również klasę BundleActivator. Wygodnie jest mieć do dyspozycji jeden centralny obiekt, który reprezentuje cykl życia i semantykę modułu dodatkowego. Należy zauważyć, że nie ma to na celu usankcjonowania praktyki pochopnego inicjowania struktur danych stosowanej dziś powszechnie w modułach dodatkowych. Podkreślamy nieustannie, że odwołanie do peryferyjnej klasy może spowodować aktywację modułu dodatkowego podczas weryfikowania klasy w innym obiekcie. Innymi słowy, sam fakt aktywowania modułu nie oznacza koniecznie, że jego funkcja jest potrzebna. Ponadto warto zauważyć, że istnieje możliwość zdefiniowania innej klasy BundleActivator lub całkowite zrezygnowanie z aktywatora pakunku.

Kroki wymagane do przeniesienia klasy Plugin z wersji 2.x do środowiska Eclipse 3.0 zależą od zadań realizowanych przez tę klasę. Jak zasygnalizowano powyżej, większa część czynności uruchomieniowych cyklu życia przypada do jednej z następujących kategorii:

Inicjowanie
Inicjowanie struktur danych i modeli odbywa się często w obrębie metody Plugin.startup(). Naturalnym, oczywistym odwzorowaniem byłoby wykonanie tych czynności w metodzie BundleActivator.start(), tzn. pozostawienie odpowiedniej funkcji w klasie Plugin. Jest to jednak rozwiązanie stanowczo niezalecane. Tak jak w przypadku modułów dodatkowych w wersji 2.x, moduły/pakunki w wersji 3.0 można uruchamiać z wielu różnych powodów w różnych okolicznościach.
Autentyczny przykład z czasów Eclipse 2.0 pomoże lepiej naświetlić omawiane zagadnienie. Utworzono moduł dodatkowy, który inicjował duży model wymagający załadowania około 11 MB kodu i wielu megabajtów danych. Dochodziło do częstych przypadków użycia, w których moduł ten aktywowano po to, żeby określić, czy ikona projektu wyświetlana w nawigatorze ma być dekorowana przy użyciu określonego znacznika. Ten test wcale nie wymagał czynności inicjujących z metody startup(), ale mimo to wszyscy użytkownicy, we wszystkich przypadkach użycia, zmuszeni byli ponosić nakłady czasu i pamięci wynikające z pochopnego inicjowania.
Podejście alternatywne polega na przeprowadzeniu inicjowania w klasycznym, niewiążącym stylu. Przykładowo, zamiast inicjować modele przy okazji aktywowania modułu dodatkowego/pakunku, można zrobić to w momencie, w którym są faktycznie potrzebne (np. w scentralizowanej metodzie akcesora modelu). W wielu przypadkach użycia te dwa momenty będą prawie tożsame, ale w innych scenariuszach podejście to pozwoli odroczyć inicjowanie (być może bezterminowo). Zaleca się dokładne przemyślenie używanej strategii inicjowania podczas migrowania modułów dodatkowych z wersji 2.1.
Rejestracja
Moment uruchomienia modułu to dogodna okazja do zarejestrowania funkcji nasłuchiwania, usług itp. oraz do uruchomienia wątków przetwarzania w tle (np. wątku nasłuchiwania gniazda). Rozsądnym miejscem wykonania tych czynności może być metoda Plugin.start(). Można również rozważyć odroczenie do momentu wystąpienia innego wyzwalacza (np. do momentu użycia określonej funkcji lub elementu danych).
Dane globalne modułu dodatkowego
Klasa Plugin może nadal pełnić tę rolę. Najważniejszą kwestią jest to, że obiekty Plugin nie są już dostępne globalnie za pośrednictwem listy zarządzanej systemowo. W środowisku Eclipse 2.x możliwe było wykrycie dowolnego obiektu Plugin modułu dodatkowego poprzez rejestr modułów dodatkowych. Nie jest to już możliwe. W większości przypadków tego rodzaju dostęp nie jest potrzebny. Obiekty Plugin, do których uzyskuje się dostęp za pośrednictwem rejestru, są najczęściej używane jako ogólne obiekty Plugin, a nie wywołujące metody specyficzne dla domeny. Równoważny poziom możliwości można osiągnąć przez dostęp do odpowiednich obiektów Bundle i manipulowanie nimi.

Rejestry i model modułu dodatkowego

W nowym środowisku wykonawczym oddziela się od siebie informacje i struktury potrzebne do wykonania modułu dodatkowego oraz informacje i struktury związane z rozszerzeniami i punktami rozszerzeń modułu. Te pierwsze są definiowane i zarządzane przez specyfikację środowiska OSGi. Te drugie są pojęciami charakterystycznymi dla środowiska Eclipse i są dodawane przez kod środowiska wykonawczego tej platformy. Z tego względu oryginalny rejestr modułów dodatkowych i obiekty pokrewne zostały podzielone na pakunki środowiska OSGi oraz rejestr rozszerzeń środowiska Eclipse.

Te elementy interfejsu IPluginRegistry, które wiążą się ze specyfikacją wykonania (np. IPluginDescriptor, ILibrary, IPrequisite), są nieaktualne, a pozostałe elementy związane z rozszerzeniami i punktami rozszerzeń zostały przeniesione do interfejsu IExtensionRegistry. Ponadto tak zwane obiekty modeli powiązane całościowo z rejestrem modułów dodatkowych są już nieaktualne. Typy te były prezentowane, a ich instancje tworzone, przez środowisko wykonawcze przede wszystkim w celu zapewnienia obsługi narzędzi takich jak PDE. Niestety, często zdarzało się, że poziom wymaganych informacji wykraczał poza możliwości lub priorytety środowiska wykonawczego (np. zapamiętywanie numerów wierszy elementów pliku plugin.xml), w związku z czym potencjalni beneficjenci tych informacji i tak musieli ostatecznie przechowywać własne struktury.

W nowym środowisku wykonawczym zrewidowano udostępnianie narzędzia. Teraz dostępne są tylko narzędzia niezbędne dla realizacji funkcji wykonawczych lub wyjątkowo trudne do uzyskania w alternatywny sposób. Jak wspomniano wyżej, obiekty modeli z rejestru modułów dodatkowych są już nieaktualne. Aktualność stracił również interfejs API analizy modułów dodatkowych. Nowy rejestr rozszerzeń umożliwia przechowywanie najistotniejszych informacji związanych z rozszerzeniami. Nowa struktura state (patrz org.eclipse.osgi.service.resolver.State i obiekty zaprzyjaźnione) reprezentuje istotne informacje związane z wykonaniem i umożliwia manipulowanie nimi.

Struktura fragmentu dla języka narodowego

W środowisku Eclipse 3.0 struktura fragmentu dla języka narodowego została zaktualizowana w celu nadania jej większej spójności. We wcześniejszych wersjach zakładano, że tłumaczenia dla plików takich jak plugin.properties znajdują się wewnątrz plików JAR dostarczanych przez fragmenty. Ponieważ oryginalne pliki znajdują się w katalogu głównym odpowiedniego modułu dodatkowego hosta, bardziej logicznym położeniem tłumaczonych plików byłby katalog główny fragmentów dla języka narodowego. Na przykład:

  org.eclipse.ui.workbench.nl/
     fragment.xml
     plugin_fr.properties
     plugin_pt_BR.properties
     ...
     nl1.jar

Warto zauważyć, że plik nl1.jar zawierałby wcześniej tłumaczenia dla pliku plugin.properties. Pliki te znajdują się obecnie w katalogu głównym fragmentu, a plik JAR zawiera tłumaczenia wszystkich tłumaczonych zasobów (tzn. plików ładowanych przez program ładujący klasy) w module dodatkowym hosta.

Oczywiście struktura fragmentu dla języka narodowego w środowisku Eclipse 2.1 jest nadal obsługiwana dla macierzystych modułów dodatkowych z wersji 2.1 uruchamianych na platformie Eclipse 3.0. Nie można jednak korzystać z fragmentu dla języka narodowego z wersji 2.1 w module dodatkowym z wersji 3.0. Należy zaktualizować fragment do nowej struktury.

Przegląd zmian w zakresie interfejsów API

org.eclipse.core.boot (pakiet org.eclipse.core.boot)

Cały pakiet org.eclipse.core.boot jest już nieaktualny. Klasa BootLoader została scalona z klasą org.eclipse.core.runtime.Platform, ponieważ podział na część startową i wykonawczą stracił uzasadnienie. Należy zauważyć, że moduł dodatkowy org.eclipse.core.boot został podzielony, a jego kod przeniesiono albo do nowego środowiska wykonawczego, albo do warstwy kompatybilności.

Interfejs IPlatformConfiguration był zawsze typem definiowanym przez komponent instalacyjny/deinstalacyjny środowiska Eclipse na potrzeby tego środowiska. Dzięki reorganizacji środowiska wykonawczego możliwe stało się przeniesienie tego typu do jego pierwotnego kontekstu. Klasa ta pozostaje w dużej części niezmieniona - została natomiast przemianowana na org.eclipse.update.configurator.IPlatformConfiguration.

Interfejs IPlatformRunnable został przeniesiony do pakietu org.eclipse.core.runtime.IPlatformRunnable.

Interfejsy IExtension oraz IExtensionPoint (pakiet org.eclipse.core.runtime)

Metoda getDeclaringPlugin() (w obu klasach) udostępnia łącze do modułu dodatkowego deklarującego rozszerzenie lub punkt rozszerzenia (odpowiednio dla wymienionych interfejsów). Nowy model rejestru rozdziela aspekt wykonawczy modułu dodatkowego od aspektu rozszerzenia lub punktu rozszerzenia i nie zawiera już interfejsu IPluginDescriptors. Użytkownicy tego interfejsu API powinni wziąć pod uwagę nową metodę getParentIdentifier() znajdującą się zarówno w interfejsie IExtension, jak i w IExtensionPoint.

Interfejsy ILibrary, IPluginDescriptor, IPluginRegistry oraz IPrerequisite (pakiet org.eclipse.core.runtime)

W oryginalnym środowisku wykonawczym rejestr modułów dodatkowych przechowywał całościowy obraz konfiguracji środowiska wykonawczego. W środowisku Eclipse 3.0 obraz ten dzieli się na środowisko OSGi i rejestr rozszerzeń. Z tego względu omawiane klasy straciły aktualność. Noty dotyczące dezaktualizacji zawierają szczegółowe instrukcje omawiające sposób aktualizowania kodu.

Obiekty Platform oraz Plugin (pakiet org.eclipse.core.runtime)

W nowym środowisku wykonawczym obiekty Plugin nie są już zarządzane przez środowisko wykonawcze, zatem nie można do nich uzyskać dostępu w sposób ogólny za pośrednictwem klasy Platform. Podobnie rejestr modułów dodatkowych nie istnieje i nie udostępnia deskryptorów modułów dodatkowych. Dostępne są jednak odpowiednie metody zastępcze, które opisano szczegółowo w dokumentacji Javadoc dotyczącej metod zdezaktualizowanych w tych klasach.

org.eclipse.core.runtime.model (pakiet org.eclipse.core.runtime.model)

Wszystkie typy w tym pakiecie są już nieaktualne. Więcej informacji można znaleźć w omówieniu rejestrów.

Interfejs IWorkspaceRunnable i metoda IWorkspace.run (pakiet org.eclipse.core.resources)

Klienci metody IWorkspace.run(IWorkspaceRunnable,IProgressMonitor) powinni zrewidować użycie tej metody i rozważyć zastosowanie poszerzonej metody IWorkspace.run(IWorkspaceRunnable,ISchedulingRule,int,IProgressMonitor). Stara metoda IWorkspace.run blokuje cały obszar roboczy na czas wykonywania interfejsu IWorkspaceRunnable. Oznacza to, że operacja wykonywana przy użyciu tej metody nigdy nie może odbywać się współbieżnie z innymi operacjami, które modyfikują obszar roboczy. W środowisku Eclipse 3.0 wiele czasochłonnych operacji zostało przeniesionych do wątków tła, więc prawdopodobieństwo konfliktów między operacjami znacznie się zwiększyło. Jeśli modalna operacja pierwszoplanowa zostanie zablokowana przez długotrwałą operację tła, interfejs użytkownika pozostanie zablokowany aż do zakończenia operacji tła lub do momentu anulowania jednej z operacji.

Zalecane rozwiązanie polega na przełączeniu wszystkich odwołań do starej metody IWorkspace.run na korzystanie z nowej metody z parametrem reguły planowania. Reguła planowania powinna cechować się największym stopniem precyzji i zawierać reguły dla wszystkich zmian przeprowadzanych przez daną operację. Jeśli operacja podejmie próbę zmodyfikowania zasobów poza zasięgiem reguły planowania, wystąpi wyjątek środowiska wykonawczego. Dokładne reguły planowania wymagane przez daną operację obszaru roboczego nie są określone i mogą zmieniać się w zależności od zainstalowanego dostawcy repozytorium w danym projekcie. Aby uzyskać regułę planowania dla operacji powodującej zmianę zasobu, należy skorzystać z fabryki IResourceRuleFactory. W razie potrzeby można skorzystać z klasy MultiRule w celu określenia wielu reguł zasobów, a za pomocą metody MultiRule.combine można wygodnie połączyć reguły z różnych operacji modyfikujących zasoby.

Jeśli nie jest wymagane stosowanie blokady, można użyć reguły planowania o wartości null. Umożliwi to modyfikowanie wszystkich zasobów w obrębie obszaru roboczego przez element uruchamialny, ale nie zapobiegnie współbieżnemu modyfikowaniu obszaru roboczego przez inne wątki. W przypadku prostych zmian w obszarze roboczym jest to często rozwiązanie najłatwiejsze i najdogodniejsze pod kątem współbieżności.

Interfejs IWorkbenchPage (pakiet org.eclipse.ui)

Interfejs IEditorDescriptor (pakiet org.eclipse.ui)

Interfejs ISharedImages (pakiet org.eclipse.ui)

Interfejs IWorkbenchActionConstants (pakiet org.eclipse.ui)

Interfejs IWorkbenchPreferenceConstants (pakiet org.eclipse.ui)

Interfejs IExportWizard (pakiet org.eclipse.ui)

Interfejs IImportWizard (pakiet org.eclipse.ui)

Interfejs INewWizard (pakiet org.eclipse.ui)

Klasa WorkbenchHelp (pakiet org.eclipse.ui.help)

Interfejs IHelp (pakiet org.eclipse.help)

Interfejs ITextEditorActionConstants (pakiet org.eclipse.ui.texteditor)

Interfejs IAbstractTextEditorHelpContextIds (pakiet org.eclipse.ui.texteditor)

Klasa BasicTextEditorActionContributor (pakiet org.eclipse.ui.texteditor)

Klasa TextEditorActionContributor (pakiet org.eclipse.ui.editors.text)

Punkt rozszerzenia annotationTypes (moduł dodatkowy org.eclipse.ui.editors)

Pojawia się obecnie wyraźne pojęcie typu adnotacji. Patrz metoda Annotation.getType() oraz Annotation.setType(). Typ adnotacji może ulec zmianie w ciągu jej cyklu życia. Dodano nowy punkt rozszerzenia dla deklaracji typu adnotacji: org.eclipse.ui.editors.annotationTypes. Typ adnotacji ma nazwę i może zostać zadeklarowany jako podtyp innego zadeklarowanego typu adnotacji. Deklaracja typu adnotacji może również korzystać z atrybutów markerType oraz markerSeverity w celu wskazania, że znaczniki określonego typu i istotności powinny być reprezentowane w edytorach tekstów jako adnotacje określonego typu. Nie należy już korzystać z atrybutów markerType oraz markerSeverity w punkcie rozszerzenia org.eclipse.ui.editors.markerAnnotationSpecification. Specyfikacje adnotacji znaczników stają się tym samym niezależne od znaczników i nazwa może być w związku z tym myląca. Została jednak zachowana, aby zapewnić kompatybilność wsteczną.

Instancje podklas klasy AbstractMarkerAnnotationModel wykrywają i ustawiają odpowiednie typy adnotacji dla adnotacji tworzonych przez siebie na bazie znaczników. Aby programowo pobrać typ adnotacji dla danego znacznika albo pary atrybutów markerType i markerSeverity, należy użyć klasy org.eclipse.ui.texteditor.AnnotationTypeLookup.

Dostęp do hierarchii typów adnotacji zapewnia interfejs IAnnotationAccessExtension. Dla danego typu adnotacji istnieje możliwość uzyskania łańcucha typów nadrzędnych i sprawdzenie, czy wybrany typ jest podtypem innego typu adnotacji. Interfejs ten implementuje klasa DefaultMarkerAnnotationAccess.

Punkt rozszerzenia markerAnnotationSpecification (moduł dodatkowy org.eclipse.ui.editors)

Typ adnotacji to klucz umożliwiający znalezienie powiązanej specyfikacji adnotacji znacznika. Tak jak typy adnotacji mogą stanowić rozszerzenie innych typów adnotacji, istnieją również niejawne powiązania między specyfikacjami adnotacji znaczników. Specyfikacja adnotacji znacznika dla danego typu adnotacji jest zatem uzupełniana przez specyfikacje dla typów nadrzędnych tego typu adnotacji. Z tego względu specyfikacje adnotacji znaczników nie muszą być kompletne, tak jak było to wymagane do tej pory. Specyfikacje są pobierane za pomocą klasy AnnotationPreferences. Korzystając z klasy org.eclipse.ui.texteditor.AnnotationPreferenceLookup, można pobrać preferencje adnotacji dla danego typu adnotacji, która umożliwia transparentne uzupełnienie preferencji na postawie łańcucha typów nadrzędnych adnotacji.

Specyfikacja adnotacji znacznika została poszerzona o trzy dodatkowe atrybuty mające na celu umożliwienie definicji niestandardowych wystąpień danego typu adnotacji na linijce pionowej. Atrybuty te to icon, symbolicIcon oraz annotationImageProvider. Wartością atrybutu icon jest ścieżka do pliku zawierającego obraz ikony. Wartością atrybutu symbolicIcon może być error, warning, info, task lub bookmark. Atrybutu symbolicIcon używa się do wskazania, że adnotacja ma być przedstawiona z użyciem tych samych obrazów, które są wykorzystywane przez platformę do prezentowania (odpowiednio) błędów, ostrzeżeń, informacji i zakładek. Wartością atrybutu annotationImageProvider jest klasa implementująca interfejs org.eclipse.ui.texteditor.IAnnotationImageProvider, która umożliwia pełną prezentację adnotacji niestandardowych.

Linijka pionowa korzysta z powiązanych z nią interfejsów IAnnotationAccess/IAnnotationAccessExtension do wyświetlenia adnotacji. Linijka pionowa nie wywołuje już metody Annotation.paint. Ogólnie nie oczekuje się już, że adnotacje będą wyświetlały się same. Metody paint oraz getLayer są już nieaktualne, co ma ostatecznie na celu uniezależnienie adnotacji od interfejsu użytkownika. Klasa DefaultMarkerAnnotationAccess służy jako domyślna implementacja interfejsu IAnnotationAccess/IAnnotationAccessExtension. Klasa DefaultMarkerAnnotationAccess implementuje następującą strategię w celu wyświetlenia adnotacji: jeśli adnotacja implementuje interfejs IAnnotationPresentation, metoda IAnnotationPresentation.paint nie zostanie wywołana. W przeciwnym razie w preferencjach adnotacji zostanie wyszukany dostawca obrazu adnotacji. Dostawca jest dostępny tylko pod warunkiem, że został określony i że moduł dodatkowy definiujący obejmującą specyfikację adnotacji znacznika został już załadowany. Jeśli dostawca obrazu adnotacji jest dostępny, zostanie do niego przekazane wywołanie. Jeśli nie, zostanie wyszukany obiekt wskazywany przez atrybut icon. Rolę ostatniej deski ratunku pełni atrybut symbolicIcon. W przypadku wyświetlania adnotacji istotna jest warstwa prezentacji adnotacji. Klasa DefaultMarkerAnnotationAccess wyszukuje warstwę prezentacji za pomocą następującej strategii: jeśli preferencja adnotacji określa warstwę prezentacji, warstwa ta zostanie użyta. Jeśli warstwa nie jest dostępna, a adnotacja implementuje interfejs IAnnotationPresentation, zostanie użyta metoda IAnnotationPresentation.getLayer. W pozostałych przypadkach zwracana jest domyślna warstwa prezentacji (tzn. 0).

Migracja do punktu rozszerzenia annotationTypes (moduł dodatkowy org.eclipse.ui.editors)

W module org.eclipse.ui.editors deklarowane są następujące typy adnotacji:

   <extension point="org.eclipse.ui.editors.annotationTypes">
      <type
         name="org.eclipse.ui.workbench.texteditor.error"
         markerType="org.eclipse.core.resources.problemmarker"
         markerSeverity="2">
      </type>
      <type
         name="org.eclipse.ui.workbench.texteditor.warning"
         markerType="org.eclipse.core.resources.problemmarker"
         markerSeverity="1">
      </type>
      <type
         name="org.eclipse.ui.workbench.texteditor.info"
         markerType="org.eclipse.core.resources.problemmarker"
         markerSeverity="0">
      </type>
      <type
         name="org.eclipse.ui.workbench.texteditor.task"
         markerType="org.eclipse.core.resources.taskmarker">
      </type>
      <type
         name="org.eclipse.ui.workbench.texteditor.bookmark"
         markerType="org.eclipse.core.resources.bookmark">
      </type>
    </extension>

Zdefiniowane rozszerzenie markerAnnotationSpecification nie udostępnia już atrybutów "markerType" i "markerSeverity". Rozszerzenia te definiują atrybut "symbolicIcon" z odpowiednią wartością. Metody MarkerAnnotation.paint oraz MarkerAnnotation.getLayer nie są już zatem wywoływane - innymi słowy, przesłonięcie tych metod nie będzie miało żadnego skutku. Klienci, których to dotyczy, powinni zaimplementować interfejs IAnnotationPresentation.

Interfejs ILaunchConfigurationType (pakiet org.eclipse.debug.core)

Wprowadzenie trybów uruchamiania rozszerzalnego w wersji 3.0 spowodowało, że dla danego typu konfiguracji startowej może występować więcej niż jeden delegat uruchamiania. Wersje wcześniejsze niż 3.0 obsługiwały tylko jednego delegata uruchamiania przypadającego na typ konfiguracji startowej. Metoda ILaunchConfigurationType.getDelegate() jest już nieaktualna. Zamiast niej należy używać metody getDelegate(String mode) do pobrania delegata uruchamiania dla danego trybu uruchomieniowego. Zdezaktualizowana metoda została zmodyfikowana, tak aby zwracała delegata uruchamiania dla trybu run.

Interfejsy ILaunchConfigurationTab oraz ILaunchConfigurationTabGroup (pakiet org.eclipse.debug.ui)

Grupy kart i karty uruchamiania nie są już powiadamianie po zakończeniu uruchamiania. Metoda launched(ILaunch) w interfejsach ILaunchConfigurationTab oraz ILaunchConfigurationTabGroup została zdezaktualizowana i nie jest już wywoływana. Poleganie na tej metodzie w zakresie funkcji uruchomieniowych było zawsze problematyczne, ponieważ karty występują tylko w przypadku, gdy uruchamianie odbywa się z poziomu okna dialogowego. Ponadto nie można już wywoływać tej metody ze względu na wprowadzenie uruchamiania w tle, ponieważ okno dialogowe uruchamiania jest zamykane przed zaistnieniem wynikowego obiektu uruchamiania.

Interfejs ILaunchConfigurationTab oraz klasa AbstractLaunchConfigurationTab (pakiet org.eclipse.debug.ui)

Do interfejsu ILaunchConfigurationTab dodano dwie metody - activated oraz deactivated. Te nowe metody cyklu życia są wywoływane w momencie (odpowiednio) wejścia na kartę i wyjścia z niej. Istniejące implementacje interfejsu ILaunchConfigurationTab, które tworzą podklasę klasy abstrakcyjnej udostępnianej przez moduł dodatkowy debugowania (AbstractLaunchConfigurationTab), są kompatybilne binarnie, ponieważ wymienione metody są zaimplementowane w tej klasie.

We wcześniejszych wersjach do karty w momencie jej aktywowania przesyłany był komunikat initializeFrom oraz komunikat performApply w momencie jej dezaktywacji. W ten sposób środowisko kart konfiguracji startowych udostępniało komunikację między kartami za pośrednictwem konfiguracji startowych (przez zaktualizowanie konfiguracji bieżącymi wartościami atrybutów przy wyjściu z karty oraz przy wejściu na kartę). Jednak ponieważ wiele kart nie wymaga komunikacji między kartami, takie podejście może być nieskuteczne. Ponadto nie było możliwości rozróżnienia między kartą właśnie aktywowaną oraz kartą wyświetlającą wybraną konfigurację startową po raz pierwszy. Nowo dodane metody pozwalają rozróżniać między aktywacją i inicjowaniem oraz dezaktywacją i zapisaniem bieżących wartości.

Domyślna implementacja metody activated udostępniana przez kartę abstrakcyjną wywołuje element initializeFrom. Domyślna implementacja metody deactivated wywołuje element performApply. Karty, które mają korzystać z nowego interfejsu API, powinny odpowiednio przesłaniać te metody. Ogólnie w przypadku kart, które nie wymagają komunikacji między kartami, zalecane podejście to ponowna implementacja tych metod, aby nie wykonywały żadnych operacji.

Typ punktu rozszerzenia launchConfigurationTabGroup (pakiet org.eclipse.debug.ui)

We wcześniejszych wersjach przełączanie perspektywy określane było w ramach konfiguracji startowej, za pośrednictwem atrybutów konfiguracji startowej ATTR_TARGET_DEBUG_PERSPECTIVE oraz ATTR_TARGET_RUN_PERSPECTIVE. Wraz z wprowadzeniem trybów uruchamiania rozszerzalnego w wersji 3.0 takie podejście nie pozwala już na skalowanie. Przełączanie perspektywy odbywa się teraz na bazie typu konfiguracji startowej według trybów uruchamiania obsługiwanych przez dany typ konfiguracji startowej. Do elementu DebugUITools dodano interfejs API służący do ustawiania i pobierania perspektywy powiązanej z typem konfiguracji startowej dla określonego typu uruchamiania.

Dodano opcjonalny element launchMode do punktu rozszerzenia launchConfigurationTabGroup, który pozwala na określenie domyślnej perspektywy dla konfiguracji startowej i typu uruchamiania przez udostępnioną grupę kart.

Z poziomu interfejsu użytkownika środowiska Eclipse użytkownicy mogą edytować perspektywy powiązane z typem konfiguracji startowej, otwierając okno dialogowe konfiguracji startowej i wybierając z drzewa węzeł typu konfiguracji (a nie pojedynczą konfigurację). Zostanie wyświetlona karta, która umożliwia ustawienie perspektywy odpowiadającej każdemu obsługiwanemu trybowi uruchamiania.

[Tylko pakiet JDT] Interfejs IVMRunner (pakiet org.eclipse.jdt.launching)

Do klasy VMRunnerConfiguration dodano dwie metody, które umożliwiają ustawianie i pobieranie zmiennych środowiskowych. Implementatorzy interfejsu IVMRunner powinni wywoływać metodę VMRunnerConfiguration.getEnvironment() i przekazywać środowisko do wykonywanej maszyny JVM. Klienci korzystający z metody DebugPlugin.exec(String[] cmdLine, File workingDirectory) mogą to zrobić, wywołując metodę DebugPlugin.exec(String[] cmdLine, File workingDirectory, String[] envp). Wystarczy po prostu przekazać wynik z metody getEnvironment().

[Tylko pakiet JDT] Klasy VMRunnerConfiguration i Bootstrap (pakiet org.eclipse.jdt.launching)

We wcześniejszych wersjach klasa VMRunnerConfiguration miała jeden atrybut służący do opisu ścieżki startowej. Atrybut jest kolekcją elementów String, które mają być podane w argumencie -Xbootclasspath. Do klasy VMRunnerConfiguration dodano trzy nowe atrybuty, aby zapewnić obsługę maszyn JVM z możliwością dołączania z przodu lub z tyłu ścieżki startowej. Nowe metody/atrybuty to:

Stary atrybut getBootClassPath() jest nadal dostępny i stanowi odpowiednik trzech nowych atrybutów z kompletną ścieżką. Elementy VMRunner, które obsługują nowe opcje ścieżki startowej, powinny jednak korzystać z nowych atrybutów.

[Tylko pakiet JDT] Ulepszona obsługa kopii roboczych (pakiet org.eclipse.jdt.core)

Narzędzie kopii roboczej modelu Java zostało zmodyfikowane w wersji 3.0 w celu udostępnienia znacznie poszerzonej funkcjonalności. W wersjach wcześniejszych niż 3.0 model Java pozwalał tworzyć pojedyncze kopie robocze jednostek kompilacji. Istniała możliwość wprowadzania zmian w kopiach roboczych i zatwierdzania ich w późniejszym terminie. Dostępna była obsługa ograniczonej analizy kopii roboczej w kontekście pozostałej części modelu Java. Nie istniała jednak możliwość uwzględnienia w tych analizach więcej niż jednej kopii roboczej naraz.

Zmiany w wersji 3.0 umożliwiają tworzenie i zarządzanie zestawami kopii roboczych jednostek kompilacji oraz wykonywanie analiz uwzględniających wszystkie kopie w zestawie. Przykładowo klient taki jak refaktoryzacja JDT może utworzyć kopie robocze jednej lub kilku jednostek kompilacji, które być może mają zostać zmodyfikowane, a następnie może rozwiązać odwołania typów między kopiami roboczymi. We wcześniejszych wersjach było to możliwe dopiero po zatwierdzeniu zmian wprowadzonych w kopiach roboczych jednostek kompilacji.

Interfejs API modelu Java zmienia się w dwóch aspektach w celu dodania ulepszonej obsługi:

(1) Funkcje znajdujące się wcześniej w interfejsie IWorkingCopy i dziedziczone przez interfejs ICompilationUnit zostały skonsolidowane w ramach interfejsu ICompilationUnit. Interfejs IWorkingCopy był używany tylko w tym miejscu, a jego zakres był dużo ogólniejszy, niż wynikałoby to z faktycznych potrzeb. Wprowadzona zmiana upraszcza interfejs API. Interfejs IWorkingCopy jest już nieaktualny. Dezaktualizacji uległy także inne miejsca w interfejsie API, w których interfejs IWorkingCopy był wykorzystywany jako parametr lub typ wyniku. Nowe metody API odwołują się do interfejsu ICompilationUnit zamiast interfejsu IWorkingCopy.

(2) Interfejs IBufferFactory został zastąpiony przez klasę WorkingCopyOwner. Ulepszona obsługa kopii roboczych wymaga obiektu, który może być ich właścicielem. Chociaż interfejs IBufferFactory znajduje się we właściwym miejscu, nazwa nie oddaje adekwatnie sposobu, w jaki działa nowy mechanizm kopii roboczych. Nazwa WorkingCopyOwner mówi dużo więcej. Dodatkowo klasa WorkingCopyOwner jest deklarowana jako klasa abstrakcyjna, a nie interfejs, aby pojęcie właściciela kopii roboczej mogło ewoluować w przyszłości. Z interfejsu IBufferFactory została przeniesiona bez zmian do klasy WorkingCopyOwner jedyna znajdująca się w nim metoda. Klasa WorkingCopyOwner nie implementuje interfejsu IBufferFactory, aby było jasne, że interfejs IBufferFactory należy już do przeszłości. Interfejs IBufferFactory jest nieaktualny. Dezaktualizacji uległy także inne miejsca w interfejsie API, w których interfejs IBufferFactory pojawia się jako parametr lub typ wyniku. Nowe metody API odwołują się do klasy WorkingCopyOwner zamiast interfejsu IBufferFactory.

Te zmiany nie naruszają kompatybilności binarnej.

Podczas migracji wszystkie odwołania do typu IWorkingCopy powinny zostać zastąpione odwołaniami do typu ICompilationUnit. Jedyna implementacja interfejsu IWorkingCopy implementuje również typ ICompilationUnit, co oznacza, że obiekty typu IWorkingCopy mogą być bezpiecznie rzutowane na typ ICompilationUnit.

Klasa implementująca interfejs IBufferFactory będzie wymagała zastąpienia przez podklasę klasy WorkingCopyOwner. Chociaż sama klasa WorkingCopyOwner nie implementuje interfejsu IBufferFactory, byłoby możliwe zadeklarowanie podklasy klasy WorkingCopyOwner, która implementuje interfejs IBufferFactory. Spowodowałoby to utworzenie pomostu między starymi i nowymi elementami (interfejs IBufferFactory deklaruje metodę createBuffer(IOpenable), a klasa WorkingCopyOwner deklaruje metodę createBuffer(ICompilationUnit); interfejs ICompilationUnit rozszerza interfejs IOpenable).

Ponieważ zmiany związane z interfejsami IWorkingCopy i IBufferFactory są ze sobą powiązane, zaleca się zajęcie nimi jednocześnie. Poniżej przedstawiono szczegóły dezaktualizacji:

Restrukturyzacja modułu dodatkowego org.eclipse.help

Moduł dodatkowy org.eclipse.help, który był używany do przechowywania interfejsów API i punktów rozszerzeń służących do dostarczania zasobów rozszerzających system pomocy, a także do wyświetlania pomocy, zawiera teraz wyłącznie interfejsy API i punkty rozszerzeń służące do dostarczania i uzyskiwania dostępu do zasobów pomocy. Część domyślnej implementacji interfejsu użytkownika pomocy zawarta w tym module dodatkowym została przeniesiona do nowego modułu dodatkowego org.eclipse.help.base wraz z interfejsami API służącymi do rozszerzania implementacji. Interfejsy API i punkty rozszerzeń przeznaczone do dostarczania interfejsów użytkownika pomocy i wyświetlania pomocy zostały przeniesione do modułu org.eclipse.ui. Restrukturyzacja pozwala na zapewnienie aplikacjom większej elastyczności w odniesieniu do systemu pomocy. Nowa struktura pozwala aplikacjom bazującym na ogólnym środowisku roboczym udostępniać własne interfejsy lub implementacje pomocy, a także całkowicie pominąć system pomocy.

Ponieważ punkty rozszerzeń i pakiety interfejsów API, których dotyczy ta restrukturyzacja, są przeznaczone tylko do użytku przez sam system pomocy, nie zachodzi prawdopodobieństwo zakłócenia istniejących modułów dodatkowych. Zostały tutaj dołączone wyłącznie dla zachowania kompletności opisu:

Nowa interfejs API na potrzeby interfejsu użytkownika wyszukiwania

W wersji 3.0 dodano nowy interfejs API umożliwiający implementowanie niestandardowych wyszukiwań. Oryginalny interfejs API jest już nieaktualny w wersji 3.0 i zaleca się migrację klientów do nowego interfejsu API w pakietach org.eclipse.search.ui oraz org.eclipse.search.ui.text.

Klienci będą musieli utworzyć implementacje interfejsów ISearchQuery, ISearchResult oraz ISearchResultPage. Implementacja interfejsu ISearchResultPage musi zostać zatem wniesiona do nowego punktu rozszerzenia org.eclipse.search.searchResultViewPages.

Domyślne implementacje interfejsów ISearchResult i ISearchResultPage są udostępniane w pakiecie org.eclipse.search.ui.text.

Komunikaty z wartością null w klasach MessageBox i DirectoryDialog (pakiet org.eclipse.swt.widgets)

Przed wprowadzeniem wersji 3.0 wywołanie metody SWT DirectoryDialog.setMessage(String string) lub MessageBox.setMessage(String string) z wartością null dla łańcucha spowodowałoby wyświetlenie okna dialogowego z tytułem niezawierającym żadnego tekstu. Zachowanie to nie wynikało ze specyfikacji (przekazywanie wartości null nie było nigdy dozwolone) i rodziło problemy z metodą getMessage, która nie może zwracać wartości null. W wersji 3.0 przekazanie wartości null powoduje teraz zgłoszenie wyjątku IllegalArgumentException, a specyfikacje zostały odpowiednio zmodyfikowane, aby odzwierciedlić to zachowanie i uspójnić z metodą w nadklasie Dialog.setMessage. Jeśli wykorzystuje się metodę Dialog.setMessage, należy się upewnić, że przekazany łańcuch nigdy nie jest wartością null. Aby uzyskać okno dialogowe bez tytułu, należy po prostu przekazać pusty łańcuch.

Ulepszenia dotyczące sygnalizacji postępu dla operacji modalnych

Obsługa operacji współbieżnych wymaga bardziej zaawansowanych sposobów sygnalizowania postępu dla operacji modalnych. W ramach ulepszania zwracanych odpowiedzi i reakcji w klasie IProgressService zaimplementowano dodatkową obsługę postępu. Nadal działa istniejący do tej pory sposób sygnalizowania postępu za pomocą klasy ProgressMonitorDialog. Jednak aby zwiększyć walory użytkowe, zaleca się migrację do nowego interfejsu IProgressService.

Odpowiednie instrukcje na ten temat zawiera dokument Showing Modal Progress in Eclipse 3.0 (Sygnalizowanie postępu dla operacji modalnych w środowisku Eclipse 3.0).

Usunięto grupy akcji debugowania

Usunięto punkt rozszerzenia grup akcji debugowania (org.eclipse.debug.ui.debugActionGroups). W wersji Eclipse 3.0 w środowisku roboczym wprowadzono obsługę działań za pośrednictwem punktu rozszerzenia org.eclipse.platform.ui.activities. Obsługa ta obejmuje wszystkie funkcje udostępniane przez grupy akcji debugowania i jest łatwiejsza w użyciu (obsługuje wzorce zamiast wyczerpującego określania wszystkich akcji). Dostępny jest również programowy interfejs API do obsługi tych funkcji. Nieusunięcie odwołań do starego punktu rozszerzenia nie spowoduje żadnych błędów. Zostaną one po prostu zignorowane. Zaleca się, aby dostawcy produktów korzystali z obsługi działań oferowanej przez środowisko robocze w celu powiązania akcji debugera specyficznych dla języka z działaniami specyficznymi dla języka (np. akcje debugera C++ można powiązać z działaniem o nazwie "Opracowywanie kodu C++").

Możliwość wyłączenia menedżera punktów zatrzymania

Interfejs IBreakpointManager definiuje teraz metody setEnabled(boolean) oraz isEnabled(). Kiedy menedżer punktów zatrzymania jest wyłączony, debugery będą ignorować wszystkie zarejestrowane punkty zatrzymania. Platforma debugowania udostępnia również nowy mechanizm nasłuchiwania, IBreakpointManagerListener, który pozwala klientom rejestrować się w ramach menedżera punktów zatrzymania w celu otrzymania powiadomienia o zmianie jego stanu. Widok Punkty zatrzymania wywołuje ten interfejs API z poziomu nowej akcji przełączania, która pozwala użytkownikom "pominąć wszystkie punkty zatrzymania". Działanie debugerów, które nie uwzględniają stanu menedżera punktów zatrzymania, będzie wyglądało na nieprawidłowe, kiedy użytkownik spróbuje skorzystać z tej funkcji.

[Tylko pakiet JDT] Uczestnicy wyszukiwania Java (pakiet org.eclipse.jdt.core.search)

Języki zbliżone do języka Java (takie jak JSP, SQLJ, JWS itd.) powinny oferować możliwość uczestnictwa w wyszukiwaniu Java. W szczególności implementatorzy takich języków powinni być w stanie:

Implementatorów tego typu określa się mianem uczestników wyszukiwania. Rozszerzają oni klasę SearchParticipant. Uczestnicy wyszukiwania są przekazywani do zapytań - patrz opis metody SearchEngine.search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor).

W przypadku indeksowania lub znajdowania dopasowań uczestnik wyszukiwania musi definiować podklasę klasy SearchDocument, która będzie w stanie pobrać treść dokumentu, przesłaniając metodę getByteContents() lub getCharContents(). Instancja tej podklasy jest zwracana przez metodę getDocument(String).

Uczestnik wyszukiwania, który chce indeksować wybrany dokument, skorzysta z metody SearchParticipant.scheduleDocumentIndexing(SearchDocument, IPath), aby zaplanować indeksowanie tego dokumentu w określonym indeksie. Kiedy dokument będzie już gotowy do indeksowania, struktura bazowa wywoła metodę SearchParticipant.indexDocument(SearchDocument, IPath). Uczestnik wyszukiwania uzyskuje następnie treść dokumentu, analizuje ją i dodaje wpisy indeksu przy użyciu metody SearchDocument.addIndexEntry(char[], char[]).

Po zakończeniu indeksowania można tworzyć zapytania bazujące na indeksach i znajdować wyniki przy użyciu metody SearchEngine.search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor). Powoduje to w pierwszej kolejności przekazanie do każdego uczestnika wyszukiwania żądania dotyczącego indeksów wymaganych do przeprowadzenia zapytania. Używana jest do tego metoda SearchParticipant.selectIndexes(SearchPattern, IJavaSearchScope). Dla każdej pozycji indeksu, która pasuje do zadanego wzorca, tworzony jest dokument wyszukiwania - w tym celu do uczestnika wyszukiwania kierowane jest odpowiednie zapytanie (patrz getDocument(String)). Wszystkie te dokumenty są przekazywane do uczestnika wyszukiwania w celu znalezienia wyników za pomocą metody locateMatches(SearchDocument[], SearchPattern, IJavaSearchScope, SearchRequestor, IProgressMonitor). Uczestnik wyszukiwania powiadamia element SearchRequestor o wynikach za pomocą metody acceptSearchMatch(SearchMatch) i przekazuje instancję podklasy klasy SearchMatch.

Uczestnik wyszukiwania może delegować część swojej pracy do domyślnego uczestnika wyszukiwania Java. Instancję tego uczestnika uzyskuje się przy użyciu metody SearchEngine.getDefaultSearchParticipant(). Na przykład uczestnik SQLJ poproszony o znalezienie dopasowań może utworzyć dokumenty .java na bazie swoich dokumentów .sqlj i delegować pracę do uczestnika domyślnego, przekazując mu te dokumenty .java.