## Linked resources

Earlier discussions of resources and the file system (Mapping resources to disk locations) assumed that all resources in a project are located in the same place in the file system. This is generally true. However, the concept of linked resources in the workbench is provided so that files and folders inside a project can be stored in the file system outside of the project's location.

Linked resources must have a project as their parent resource. They can be located virtually anywhere in the file system. They can reside outside the project location, or even within another project. There are only a few restrictions on linked resource locations. The method IWorkspace.validateLinkLocation can be used to ensure that a given location is valid for creating a linked resource.

Linked resources are created using the method IFolder.createLink or IFile.createLink. To determine programmatically whether a given resource is a linked resource, you can use the method IResource.isLinked. Note that this method will only return `true` for linked resources, not for children of linked resources.

Apart from these special methods for creating linked resources and finding out if a resource is linked, you can use normal workspace API when manipulating linked resources. In most respects, linked resources act exactly like any other resource in the workspace. However, some restrictions apply when moving, copying, or deleting linked resources. See IResource and its sub-classes for information on individual operatiosn and their limitations.

### Path variables

Path variables can be used when specifying the location of linked resources. A path variable is a simple (String -> IPath) mapping that defines a shortcut for a location in the file system. Variables can ease the management of linked resources by reducing the number of places where hard-coded, absolute file system paths are used.

Path variables streamline the management of linked resources for users in several ways:

- Allows a single reference to the absolute path when defining several linked resources under a common root
- Allows the location of several resources to be redefined by changing a single variable
- Allows users to share projects containing linked resources without updating the paths of each resource (since the absolute path can vary from one machine to another.)

The last item in this list deserves a bit of explanation. When a user creates a linked resource in a project, a description of the linked resource is added to the project description file (".project") in the project's location. By using a path variable, users can share a project (by copying the project's content or by using a repository), and redefine the variable to suit each individual workstation. For example, one user might store external resources under c:\temp on one system, while another user using Unix might store the same resources in /home/username/tmp. Defining a path variable on each workspace (`TEMP=c:\temp` and `TEMP=/home/userb/tmp)` allows users to work around this difference and share the projects with linked resources as is.

IPathVariableManager defines the API for creating, manipulating, and resolving path variables. It also provides methods for validating variable names and values before creating them, and for installing a listener to be notified when path variable definitions change. You can obtain an instance of this class using IWorkspace.getPathVariableManager. See the code examples at the end of this section for more detail.

The method IResource.getRawLocation can be used to find out the unresolved location of a linked resource. That is, to get the actual path variable name instead of resolving it to its value. If a resource location is not defined with a path variable, the getRawLocation method acts exactly like the getLocation method.

### Broken links

Clients that manipulate resources programmatically need to be aware of the possibility of broken links. Broken links occur when a linked resource's location does not exist, or is specified relative to an undefined path variable. The following special cases apply when using IResource protocol:

- The copy and move methods will fail when called on broken links.
- Calling refreshLocal on a broken link will not cause the resource to be removed from the workspace, as it does for normal resources that are missing from the file system.
- The method getLocation will return `null` for linked resources whose locations are relative to undefined path variables.
- You can still use delete to remove broken links from the workspace.

### Compatibility with installed plug-ins

Some plug-ins may not be able to handle linked resources, so there are a number of mechanisms available for disabling them. If you are writing a plug-in that absolutely needs all of a project's contents to be located in the project's default location, you can use these mechanisms to prevent users from creating linked resources where you don't want them to appear.

The first mechanism is called the project nature veto. If you define your own project nature, you can specify in the nature definition that the nature is not compatible with linked resources. Here is an example of a nature definition that employs the nature veto:

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

The second mechanism for preventing linked resource creation is the team hook. If you define your own repository implementation, you can make use of the org.eclipse.core.resources.teamHook extension point to prevent the creation of linked resources in projects that are shared with your repository type. By default, repository providers do not allow linked resources in projects connected to the repository.

If the repository support is provided by an older plug-in that is not aware of linked resources, you will not be able to create linked resources in those projects.

Finally, there is a preference setting that can be used to disable linked resources for the entire workspace. While the previous two veto mechanisms work on a per-project basis, this preference affects all projects in the workspace. To set this preference programatically, use the preference `ResourcesPlugin.PREF_DISABLE_LINKING`. Note that even when set, users or plug-ins can override this by turning the preference off.

### Linked resources in code

Let's go into some examples of using linked resources in code. We'll start by defining a path variable:

       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 {
          //invalid name or value, throw an exception or warn user
       }

Now we can create a linked resource relative to the defined path variable:

       IProject project = workspace.getProject("Project");//assume this exists
       IFolder link = project.getFolder("Link");
       IPath location = new Path("TEMP/folder");
       if (workspace.validateLinkLocation(location).isOK()) {
          link.createLink(location, IResource.NONE, null);
       } else {
          //invalid location, throw an exception or warn user
       }

That's it! You now have a linked folder in your workspace called "Link" that is located at "c:\temp\folder".

Let's end with some code snippets on this linked resource to illustrate the behavior other methods related to linked resources:

       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"