Zasoby i lokalny system plików

Kiedy platforma jest uruchomiona, a moduł dodatkowy zasobów jest aktywny, obszar roboczy jest reprezentowany przez instancję interfejsu IWorkspace, który udostępnia protokół umożliwiający uzyskanie dostępu do zawartych w nim zasobów. Instancja interfejsu IWorkspace reprezentuje powiązaną kolekcję plików i katalogów w lokalnym systemie plików. Dostęp do obszaru roboczego można uzyskać z poziomu klasy modułu dodatkowego zasobów (zdefiniowanej w pakiecie org.eclipse.core.resources).

   IWorkspace workspace = ResourcesPlugin.getWorkspace();

Jeśli moduł dodatkowy zasobów nie jest uruchomiony, obszar roboczy istnieje wyłącznie w lokalnym systemie plików, a użytkownik może go wyświetlać i manipulować nim przy użyciu standardowych narzędzi operujących na plikach. Przy omawianiu interfejsu API modułu dodatkowego zasobów zaprezentowana zostanie również struktura obszaru roboczego na dysku.

Przykładowe drzewo na dysku

Podczas instalacji pakietu SDK platformy użytkownik rozpakowuje pliki do wybranego przez siebie katalogu. Katalog ten będzie dalej określany jako katalog główny platformy. W tym katalogu znajduje się między innymi katalog plugins. W katalogu głównym znajduje się również katalog workspace, który służy do przechowywania zasobów tworzonych i używanych przez platformę. Po otwarciu katalogu workspace widoczne są w nim oddzielne podkatalogi dla każdego projektu istniejącego w obszarze roboczym. Podkatalogi te zawierają foldery i pliki zawarte w poszczególnych projektach.

Jeśli pakiet SDK zostanie zainstalowany w katalogu c:\MySDK, wówczas w katalogu c:\MySDK\workspace znajdą się podkatalogi o nazwach odpowiadających nazwom projektów w obszarze roboczym: MyWeb oraz MyServlet. Katalogi te określa się mianem katalogów treści projektów. Katalogi treści są tworzone przez platformę w momencie tworzenia projektu przez użytkownika.

W każdym katalogu znajdują się pliki i foldery składające się na dany projekt i rozmieszczone dokładnie tak samo, jak w drzewie zasobów w obszarze roboczym. Wszystkie nazwy plików są takie same, identyczna jest również treść tych plików, niezależnie od tego, czy dostęp uzyskuje się z poziomu systemu plików czy też z obszaru roboczego. Jedynym wyjątkiem jest plik .project, który zostanie omówiony w dalszej części.

   C:\MySDK\workspace  (katalog główny obszaru roboczego)
      .metadata\ (katalog metadanych platformy)
      MyWeb\ (katalog treści projektu MyWeb)
	 .project
         index.html
         images\
            logo.png
      MyServlet\ (katalog treści projektu MyServlet)
	 .project
         src\
            main.java
         bin\
            main.class

Platforma ma specjalny katalog .metadata, w którym przechowywane są wewnętrzne informacje platformy. Katalog .metadata obszaru roboczego jest swego rodzaju "czarną skrzynką". Przechowywane są w nim ważne informacje dotyczące struktury obszaru roboczego, takie jak odwołania projektu lub właściwości zasobu. Dostęp do tych danych powinien być uzyskiwany wyłącznie przy użyciu odpowiednich narzędzi za pośrednictwem interfejsu API platformy.  Pliki te nie powinny być nigdy edytowane ani nie należy nimi manipulować przy użyciu ogólnego interfejsu API systemu plików.

Dodatkowo każdy projekt ma własny plik .project, w którym przechowywane są metadane dotyczące projektu. Plik ten stanowi w zasadzie przechowywany na dysku odpowiednik informacji znajdujących się w interfejsie IProjectDescription projektu.  

Oprócz katalogu .metadata oraz plików .project foldery i pliki w katalogu obszaru roboczego są dostępne do użytku dla innych narzędzi.  Plikami i folderami można manipulować przy użyciu narzędzi, które nie są zintegrowane z platformą, np. edytorów tekstu lub systemowych programów narzędziowych. Należy jedynie pamiętać o konieczności zachowania ostrożności podczas edytowania tych plików, tak w środowisku roboczym, jak i zewnętrznie (nie różni się to niczym od sytuacji, w której użytkownik edytuje plik za pomocą dwóch niezależnych narzędzi). Środowisko robocze udostępnia operacje odświeżania, umożliwiające uzgodnienie widoku zasobów w obszarze roboczym z ich faktycznym stanem w systemie plików. Obszar roboczy jest okresowo odświeżany w celu odzwierciedlenia stanu systemu plików.

Przykładowe drzewo w kodzie

Interfejs API zasobów umożliwia manipulowanie drzewem zasobów w kodzie. Przedstawionych zostanie tu kilka fragmentów kodu, które pozwolą uzyskać lepsze zrozumienie tego interfejsu API. Interfejs API zasobów jest definiowany w ramach zestawu interfejsów w pakiecie org.eclipse.core.resources. Dostępne są interfejsy dla wszystkich typów zasobów, takich jak IProject, IFolder czy IFile. Rozbudowany wspólny protokół jest zdefiniowany w interfejsie IResource. Użyty zostanie również interfejs IPath z pakietu org.eclipse.core.runtime, który reprezentuje ścieżki z podziałem na segmenty, na przykład ścieżki do zasobów oraz ścieżki systemu plików.

Manipulowanie zasobami przypomina manipulowanie plikami przy użyciu funkcji java.io.File. Interfejs API bazuje na uchwytach.  Użycie funkcji interfejsu API takiej jak getProject czy getFolder powoduje zwrócenie uchwytu zasobu.  Nie ma gwarancji, że dany zasób istnieje (ani nie jest to wymagane), dopóki użytkownik nie spróbuje użyć takiego uchwytu. Jeśli spodziewane jest istnienie zasobu, można skorzystać z metody exists, aby się co do tego upewnić.  

Aby nawigować w obszarze roboczym z poziomu modułu dodatkowego, należy najpierw uzyskać interfejs IWorkspaceRoot, który reprezentuje najwyższy poziom hierarchii zasobów w obszarze roboczym.

   IWorkspaceRoot myWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot();

Po uzyskaniu głównego poziomu obszaru roboczego można już uzyskać dostęp do projektów w obszarze roboczym.

   IProject myWebProject = myWorkspaceRoot.getProject("MyWeb");
   // w razie potrzeby otwarcie
   if (myWebProject.exists() && !myWebProject.isOpen())
      myWebProject.open(null);

Zanim możliwa będzie praca z projektem, należy go otworzyć. Otwarcie projektu powoduje odczytanie jego struktury z dysku i utworzenie w pamięci obiektu reprezentującego drzewo zasobów projektu. Otwarcie projektu to operacja o charakterze jawnym, ponieważ każdy otwarty projekt korzysta z pamięci w celu wewnętrznego przedstawienia drzewa zasobów, a otwarte projekty uczestniczą w różnych zdarzeniach związanych z cyklem życia zasobu (np. budowaniu), które mogą być czasochłonne. Nie można zasadniczo uzyskać dostępu do zamkniętych projektów - będą wyświetlane jako puste projekty, nawet jeśli odpowiadające im zasoby wciąż istnieją w systemie plików.

Należy zauważyć, że podczas manipulowania zasobami wiele z tych przykładowych zasobów przekazuje parametr null. Wiele operacji na zasobach może powodować znaczne obciążenie systemu, dlatego towarzyszy im raportowanie postępu i możliwość anulowania przez użytkownika. Jeśli tworzony kod dysponuje interfejsem użytkownika, przekazuje się zwykle interfejs IProgressMonitor, który pozwala modułowi dodatkowemu zasobów raportować postęp podczas pracy z zasobem i umożliwia w razie potrzeby anulowanie operacji przez użytkownika.  W tym przykładzie przekazana zostanie po prostu wartość null, oznaczającą brak monitora postępu.

Kiedy projekt jest już otwarty, można uzyskać dostęp do jego folderów i plików, a także tworzyć dodatkowe. W przedstawionym poniżej przykładzie utworzony zostanie zasób plikowy na bazie treści pliku znajdującego się poza obszarem roboczym.

   IFolder imagesFolder = myWebProject.getFolder("images");
   if (imagesFolder.exists()) {
      // utworzenie nowego pliku
      IFile newLogo = imagesFolder.getFile("newLogo.png");
      FileInputStream fileStream = new FileInputStream(
         "c:/MyOtherData/newLogo.png");
      newLogo.create(fileStream, false, null);
      // metoda create zamyka strumień pliku
   }

W powyższym przykładzie w pierwszym wierszu uzyskiwany jest uchwyt do folderu obrazów. Należy sprawdzić, czy folder istnieje (exists), zanim będzie można z nim pracować. Podobnie przy pobieraniu pliku newLogo uchwyt nie reprezentuje rzeczywistego pliku, dopóki plik nie zostanie utworzony w ostatnim wierszu.  W tym przykładzie plik tworzony jest przez zapełnienie go treścią pliku logo.png.

Następny fragment kodu jest podobny do poprzedniego. Różnica polega na tym, że zamiast tworzyć nowy plik na bazie treści starego, plik newLogo jest kopiowany z oryginalnego logo.

   IFile logo = imagesFolder.getFile("logo.png");
   if (logo.exists()) {
      IPath newLogoPath = new Path("newLogo.png");
      logo.copy(newLogoPath, false, null);
      IFile newLogo = imagesFolder.getFile("newLogo.png");
      ...
   }

Na koniec utworzony zostanie kolejny folder obrazów i przeniesiony zostanie do niego nowo utworzony plik. Efektem ubocznym przeniesienia pliku będzie zmiana jego nazwy.

   ...
   IFolder newImagesFolder = myWebProject.getFolder("newimages");
   newImagesFolder.create(false, true, null);
   IPath renamedPath = newImagesFolder.getFullPath().append("renamedLogo.png");
   newLogo.move(renamedPath, false, null);
   IFile renamedLogo = newImagesFolder.getFile("renamedLogo.png");

Wiele metod interfejsu API zasobów zawiera flagę boolowską force, która określa, czy zasoby niezsynchronizowane z odpowiadającymi im plikami w lokalnym systemie plików zostaną zaktualizowane. Więcej informacji na ten temat zawiera sekcja IResource. Można również użyć metody IResource.isSynchronized, aby ustalić, czy określony zasób jest zsynchronizowany z systemem plików.

Odwzorowywanie zasobów na położenia na dysku

W przykładowym drzewie zasobów założono, że wszystkie katalogi treści projektu znajdują się w katalogu workspace, poniżej katalogu głównego platformy (C:\MySDK\workspace). Jest to domyślna konfiguracja projektów. Można jednak zmienić odwzorowanie katalogu treści projektu na dowolny katalog w systemie plików, nawet na innym dysku.

Dzięki możliwości odwzorowania położenia wybranego projektu niezależnie od innych projektów użytkownik może przechowywać treść projektu w miejscu, które odpowiada charakterowi tego projektu i wymaganiom zespołu projektowego. Katalog treści projektu należy traktować jako "katalog otwarty". Oznacza to, że użytkownicy mogą tworzyć, modyfikować i usuwać zasoby przy użyciu środowiska roboczego i modułów dodatkowych lub bezpośrednio za pomocą narzędzi i edytorów operujących na systemie plików.

Nazwy ścieżek do zasobów nie są kompletnymi ścieżkami systemu plików. Ścieżki zasobów zawsze zależą od położenia projektu (zwykle jest to katalog workspace). Aby uzyskać pełną ścieżkę systemu plików do zasobu, należy wygenerować zapytanie o jego położenie przy użyciu metody IResource.getLocation. Nie można jednak skorzystać z metody IProjectDescription.setLocation do zmiany położenia, ponieważ jest to po prostu metoda ustawiająca struktury danych.  

Również odwrotnie, aby uzyskać odpowiedni obiekt zasobu przy zadanej ścieżce systemu plików, można użyć metody IWorkspaceRoot.getFileForLocation lub IWorkspaceRoot.getContainerForLocation.

Interfejs API zasobów i system plików

Przy korzystaniu z interfejsu API zasobów do modyfikowania drzewa zasobów obszaru roboczego, oprócz aktualizacji obiektów zasobów modyfikowane są również pliki w systemie plików. A jak przedstawia się kwestia zmian w plikach zasobów wykonywanych poza interfejsem API platformy?

Zmiany zasobów dokonywane zewnętrznie nie zostaną odzwierciedlone w obszarze roboczym i obiektach zasobów, dopóki nie zostaną wykryte przez moduł dodatkowy zasobów. Moduł ten korzysta również z mechanizmu odpowiedniego dla każdego rodzimego systemu operacyjnego w celu wykrycia zewnętrznych zmian wprowadzonych w systemie plików. Dodatkowo klienci mogą korzystać z interfejsu API zasobów do uzgadniania obszaru roboczego i obiektów zasobów z lokalnym systemem plików dyskretnie i bez konieczności interwencji ze strony użytkownika. Użytkownik może również jawnie wymusić odświeżanie w widoku nawigatora zasobów w środowisku roboczym.

Wiele z metod interfejsów API zasobów zawiera parametr force, który określa sposób obsługi zasobów niezsynchronizowanych z systemem plików. Szczegółowe informacje na temat tego parametru można znaleźć w informacjach dodatkowych na temat interfejsów API dla poszczególnych metod. Dodatkowe metody w interfejsie API umożliwiają programowe sterowanie funkcją odświeżania systemu plików, na przykład IResource.refreshLocal(int depth, IProgressMonitor monitor). Informacje na temat poprawnej składni i kosztów zawiera sekcja IResource.

W modułach dodatkowych, które mają dostarczać własny mechanizm okresowego odświeżania obszaru roboczego na podstawie stanu zewnętrznego systemu plików, można skorzystać z punktu rozszerzenia org.eclipse.core.resources.refreshProviders. Więcej informacji na ten temat zawiera sekcja Dostawcy odświeżania.