Dowiązane zasoby

We wcześniejszym omówieniu zasobów i systemu plików (Odwzorowywanie zasobów na położenia na dysku) założono, że wszystkie zasoby w projekcie znajdują się w tym samym miejscu w systemie plików. Założenie to jest zwykle spełnione.  Przewidziano jednak możliwość zasobów dowiązanych w środowisku roboczym, dzięki czemu pliki i foldery składające się na projekt można przechowywać w systemie plików poza położeniem projektu. 

Dowiązane zasoby muszą mieć projekt jako zasób nadrzędny. Mogą znajdować się niemal w dowolnym miejscu w systemie plików. Mogą być przechowywane poza położeniem projektu, a nawet w obrębie innego projektu. Do położenia zasobów dowiązanych stosuje się jedynie kilka ograniczeń. Korzystając z metody IWorkspace.validateLinkLocation, można upewnić się, że wybrane położenie jest poprawne i że można w nim utworzyć zasób dowiązany.

Zasoby dowiązane tworzy się przy użyciu metod IFolder.createLink lub IFile.createLink. Aby określić w sposób programowy, czy dany zasób jest zasobem dowiązanym, można posłużyć się metodą IResource.isLinked. Należy pamiętać, że metoda ta zwraca wartość true tylko dla zasobów dowiązanych, a nie elementów potomnych tych zasobów.

Oprócz wymienionych wyżej specjalnych metod służących do tworzenia zasobów dowiązanych i sprawdzania, czy dany zasób jest zasobem dowiązanym, podczas pracy z takimi zasobami można korzystać ze zwykłych interfejsów API obszaru roboczego. Zasoby dowiązane zachowują się pod wieloma względami dokładnie tak, jak wszystkie inne zasoby w obszarze roboczym. Podczas przenoszenia, kopiowania i usuwania zasobów dowiązanych obowiązują jednak pewne ograniczenia. Aby uzyskać informacje na temat poszczególnych operacji i obowiązujących w ich przypadku ograniczeń, należy zapoznać się z interfejsem IResource i jego podklasami.

Zmienne ścieżek

Zmienne ścieżek wykorzystuje się podczas określania położenia zasobów dowiązanych. Zmienna ścieżki to proste odwzorowanie (String -> IPath), które określa skrót do położenia w systemie plików. Zmienne mogą ułatwić zarządzanie zasobami dowiązanymi, redukując liczbę wystąpień, w których stosuje się zapisane na stałe bezwzględne ścieżki systemu plików.

Zmienne ścieżek usprawniają zarządzanie zasobami dowiązanymi na kilka sposobów:

Ostatni punkt wymaga pewnego wyjaśnienia. Gdy użytkownik tworzy zasób dowiązany w projekcie, do pliku opisu projektu (".project") w położeniu projektu dodawany jest opis tego zasobu. Korzystając ze zmiennej ścieżki, użytkownicy mogą współużytkować projekt (poprzez skopiowanie treści projektu lub zastosowanie repozytorium) i ponownie zdefiniować zmienną w celu dostosowania jej do poszczególnych stacji roboczych. Przykładowo jeden użytkownik może przechowywać zasoby zewnętrzne w katalogu c:\temp systemu, a inny użytkownik, pracujący w systemie Unix, może przechowywać te same zasoby w katalogu /home/username/tmp. Zdefiniowanie zmiennej ścieżki w obu obszarach roboczych (TEMP=c:\temp oraz TEMP=/home/userb/tmp) pozwala użytkownikom obejść różnice i wygodnie współużytkować projekty z zasobami dowiązanymi.

Interfejs IPathVariableManager definiuje interfejs API służący do tworzenia i tłumaczenia zmiennych ścieżek oraz manipulowania nimi. Udostępnia również metody umożliwiające sprawdzanie poprawności wartości i nazw zmiennych przed ich utworzeniem, a także instalowanie funkcji nasłuchiwania, które umożliwiają odbieranie powiadomień o zmianach w zakresie definicji zmiennych ścieżek. Instancję tej klasy można uzyskać przy użyciu metody IWorkspace.getPathVariableManager. Więcej szczegółowych informacji można znaleźć w przykładach kodu pod koniec tej sekcji.

Za pomocą metody IResource.getRawLocation można zidentyfikować nierozpoznane położenie zasobu dowiązanego. Innymi słowy, można pobrać faktyczną nazwę zmiennej ścieżki zamiast tłumaczyć ją na odpowiednią wartość. Jeśli położenie zasobu nie jest zdefiniowane przy użyciu zmiennej ścieżki, metoda getRawLocation zachowuje się dokładnie tak jak metoda getLocation.

Zerwane dowiązania

Klienci manipulujący zasobami w sposób programowy powinni zdawać sobie sprawę z możliwości wystąpienia zerwanych dowiązań. Zerwane dowiązania występują w sytuacji, gdy położenie zasobu dowiązanego nie istnieje lub jest określone względem niezdefiniowanej zmiennej ścieżki. Podczas korzystania z protokołu interfejsu IResource mogą wystąpić następujące przypadki szczególne:

Zgodność z zainstalowanymi modułami dodatkowymi

Niektóre moduły dodatkowe mogą nie obsługiwać zasobów dowiązanych, dlatego udostępniono kilka mechanizmów służących do ich wyłączania. Jeśli tworzony jest moduł dodatkowy, który bezwzględnie wymaga zlokalizowania całej treści projektu w jego domyślnym położeniu, można użyć tych mechanizmów, aby uniemożliwić użytkownikom tworzenie zasobów dowiązanych w miejscach, w których nie powinny się znaleźć.

Pierwszy mechanizm określany jest mianem veto natury projektu. Jeśli użytkownik tworzy własną naturę projektu, może wskazać w jej definicji, że natura ta nie jest zgodna z zasobami dowiązanymi. Poniżej przedstawiono przykład definicji natury, w której zastosowano omawiany mechanizm:

   <extension
	id="myNature"
	name="Moja natura"
	point="org.eclipse.core.resources.natures">
	<runtime>
		<run class="com.xyz.MyNature"/>
	</runtime>
	<options allowLinking="false"/>
    </extension>

Drugi mechanizm zapobiegający tworzeniu zasobów dowiązanych to hak zespołu. Jeśli definiuje się własną implementację repozytorium, można skorzystać z punktu rozszerzenia org.eclipse.core.resources.teamHook w celu zablokowania możliwości tworzenia zasobów dowiązanych w projektach, które są współużytkowane wraz z danym typem repozytorium. Domyślnie dostawcy repozytoriów nie pozwalają na stosowanie zasobów dowiązanych w projektach połączonych z repozytorium. 

Jeśli obsługa repozytorium jest udostępniana przez starszy moduł dodatkowy, który nie wykrywa zasobów dowiązanych, nie będzie możliwe tworzenie takich zasobów w projektach. 

Należy jeszcze wspomnieć, że istnieje ustawienie preferencji, za pomocą którego można wyłączyć zasoby dowiązane w całym obszarze roboczym. Poprzednie dwa mechanizmy działają w odniesieniu do poszczególnych projektów, ale ten mechanizm wpływa na wszystkie projekty w obszarze roboczym. Aby ustawić omawianą preferencję programowo, należy użyć preferencji ResourcesPlugin.PREF_DISABLE_LINKING. Warto zwrócić uwagę, że nawet jeśli preferencja ta jest włączona, użytkownicy lub moduły dodatkowe mogą ją przesłonić i wyłączyć.

Zasoby dowiązane w kodzie

Przeanalizowanych zostanie teraz kilka przykładów zastosowania zasobów dowiązanych w kodzie. Na początek zdefiniowana zostanie zmienna ścieżki:

      IWorkspace workspace = ResourcesPlugin.getWorkspace();
   IPathVariableManager pathMan = workspace.getPathVariableManager();
   String name = "TEMP";
   IPath value = new Path("c:\\temp");
   if (pathMan.validateName(name).isOK() && pathMan.validateValue(value).isOK()) {
      pathMan.setValue(name, value);
   } else {
      //w razie niepoprawnej nazwy lub wartości nastąpi zgłoszenie wyjątku lub ostrzeżenie użytkownika
   }

Teraz można utworzyć zasób dowiązany określony względem zdefiniowanej zmiennej ścieżki:

      IProject project = workspace.getProject("Project");//zakładamy, że istnieje
   IFolder link = project.getFolder("Link");
   IPath location = new Path("TEMP/folder");
   if (workspace.validateLinkLocation(location).isOK()) {
      link.createLink(location, IResource.NONE, null);
   } else {
      //w razie niepoprawnego położenia nastąpi zgłoszenie wyjątku lub ostrzeżenie użytkownika
   }

Dzięki temu w obszarze roboczym dostępny jest teraz dowiązany folder o nazwie "Link", który znajduje się w katalogu "c:\temp\folder".

Na koniec przedstawionych zostanie kilka fragmentów kodu odnoszących się do tego zasobu, aby zilustrować zachowanie innych metod związane z zasobami dowiązanymi:

   link.getFullPath() ==> "/Project/Link"
   link.getLocation() ==> "c:\temp\folder"
   link.getRawLocation() ==> "TEMP/folder"
   link.isLinked() ==> "true"
   
   IFile child = link.getFile("abc.txt");
   child.create(...);
   child.getFullPath() ==> "/Project/Link/abc.txt"
   child.getLocation() ==> "c:\temp\folder\abc.txt"
   child.getRawLocation() ==> "c:\temp\folder\abc.txt"
   child.isLinked() ==> "false"