platform-vcm-home/docs/online/team3.1/logical-physical-mappings.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (download) (as text) (annotate)
Fri Feb 11 21:38:21 2005 UTC (4 years, 9 months ago) by mvalenta
Branch: MAIN
Changes since 1.3: +27 -25 lines
*** empty log message ***
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <title>Support Logical Resources: Resource Mappings</title>
</head>
<body>
<table border="0" cellspacing="5" cellpadding="2" width="100%">
  <tbody>
    <tr>
      <td align="left" valign="top" bgcolor="#0080c0"> <b><font
 color="#ffffff" face="Arial,Helvetica"> Eclipse 3.1 - Support Logical Resources 
        - Resource Mappings</font></b></td>
    </tr>
  </tbody>
</table>
<h1>Support Logical Resources - Resource Mappings</h1>
This document outlines the chosen solution to the adaptables problem outlined 
in the <a href="logical-physical-public.html"><strong>Support Logical Resources</strong></a> 
plan item problem description document. Feedback is strongly encouraged and may 
be provided on the platform-team-dev mailing list or in the <a
 href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=37723">bug report</a> for 
this plan item. The API described in this document is not yet final and may undergo 
some revision before the end of the Eclipse 3.1 development cycle.
<h3>The Basic Resource Mapping API</h3>
<p>This solution involves adding API to the Resources plugin that maps logical 
  models elements to workspace (i.e. file system) resources. The API is purposely 
  simple with logical model manipulations omitted. A client can't use this interface 
  to display logical models or gain any interesting additional knowledge about 
  it. It's purpose is simply to map one or more model elements to workspace resources. 
</p>
<p>The API consists of the following classes: </p>
<ul>
  <li><strong>ResourceMapping</strong>: The Class to which logical model elements 
    adapt to indicate that the model corresponds to a set of resources in the 
    workspace. The complete <code>ResourceMapping</code> class can be viewed <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.core.resources/src/org/eclipse/core/resources/mapping/ResourceMapping.java?rev=HEAD&content-type=text/vnd.viewcvs-markup">here</a>. 
    The methods of interest are: 
    <ul>
      <li><code>Object getModelObject()</code>: The model object from which the 
        mapping was derived (or adapted).</li>
      <li><code>ResourceTraversal[] getTraversals(ResourceMappingContext, IProgressMonitor)</code>: 
        The resource traversal that cover the resources that constitute the model 
        object.</li>
    </ul>
  </li>
  <li><strong>ResourceTraversal</strong>: A <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.core.resources/src/org/eclipse/core/resources/mapping/ResourceTraversal.java?rev=HEAD&content-type=text/vnd.viewcvs-markup"><code>ResourceTraversal</code></a> 
    contains a set of resources and a depth flag that indicates the depth to which 
    the resources in the traversal are associated with the originating model object. 
    Resource traversals are provided to a client by a resource mapping in order 
    to describe the contents of a model in such a way that the client (e.g a repository 
    provider) can perform its operations in as efficient a means as possible. 
    Methods of interest are: 
    <ul>
      <li><code>getResources()</code></li>
      <li><code>getDepth()</code></li>
    </ul>
  </li>
  <li><strong>ResourceMappingContext</strong>: a context that is provided to the 
    resource mapping by the client when obtaining traversals. This context allows 
    the logical model to determine what the remote state of the model is so that 
    the proper resources can be covered by the resource traversals returned by 
    the resource mapping. The use of the<code> <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.core.resources/src/org/eclipse/core/resources/mapping/ResourceMappingContext.java?rev=HEAD&content-type=text/vnd.viewcvs-markup">ResourceMappingContext</a></code> 
    is a bit more complicated and is described <a href="#ResourceMappingContext">later</a>.</li>
</ul>
<p>There are two types of plugins that should be interested in resource mappings. 
  Those who provide a model that consists of, or is persisted in, resources in 
  the workspace and those that want to perform operations on resources. The following 
  two sections describe how to associate a resource mapping with a model object 
  and how to contribute menus to objects that adapt to resource mappings.</p>
<h4>Adapting a Model to a ResourceMapping</h4>
<p>Plugins that adapted their model objects to <code>IResource</code> in order 
  to get resource specific actions shown in the context menu can now adapt to 
  <code>ResourceMapping</code> if a richer description of how the object adapts 
  to resources is benefitial. However, they are not required to do so if there 
  is no benefit. For instance a Java compilation unit (i.e. *.java file shown 
  in a JDT view) that now currently adapts to <code>IFile</code> need not adapt 
  to <code>ResourceMapping</code> since nothing is gained. However, a Java package 
  should adapt to <code>ResourceMapping</code> in order to indicate that the package 
  is only the files in the corresponding folder and not the subfolders.</p>
<p>The preferred way to adapt model elements to a resource mapping is to use an 
  adapter factory. The following is the XML markup for contributing an adapter 
  factory in a plugin manifest. </p>
<pre style="background-color: rgb(204, 204, 255);">   &lt;extension<br>         point=&quot;org.eclipse.core.runtime.adapters&quot;&gt;<br>      &lt;factory<br>            class=&quot;org.eclipse.example.library.logical.AdapterFactory&quot;<br>            adaptableType=&quot;org.eclipse.example.library.Book&quot;&gt;<br>         &lt;adapter type=&quot;org.eclipse.core.resources.mapping.ResourceMapping&quot;/&gt;<br>      &lt;/factory&gt;<br>      &lt;factory<br>            class=&quot;org.eclipse.example.library.logical.AdapterFactory&quot;<br>            adaptableType=&quot;org.eclipse.example.library.Library&quot;&gt;<br>         &lt;adapter type=&quot;org.eclipse.core.resources.mapping.ResourceMapping&quot;/&gt;<br>      &lt;/factory&gt;<br>      ...<br>   &lt;/extension&gt;</pre>
<p>The adapter factory implementation would look something like this:</p>
<pre style="background-color: rgb(204, 204, 255);">public class AdapterFactory implements IAdapterFactory {
   public Object getAdapter(Object adaptableObject, Class adapterType) {
      if((adaptableObject instanceof EObject) && adapterType == ResourceMapping.class) {
         return new EMFResourceMapping((EObject)adaptableObject);
      }
      return null;
   }

   public Class[] getAdapterList() {
      return new Class[] {ResourceMapping.class};
   }
}</pre>
<p>For popup menu contribuions, it is not required that the model objects implement 
  the <code>IAdaptable</code> interface. However, if they do, they must ensure 
  that the Platform adapter manager is consulted. This can be done by either subclassing 
  <code>PlatformObject</code> or by using the following line of code:</p>
<blockquote> 
  <p><code>Platform.getAdapterManager().getAdapter(Object, Class)</code></p>
</blockquote>
<p>The above is the preferrable approach. However, the model object can implement 
  the IAdaptable interface and provide a <code>getAdapter(Class)</code> implementation 
  that creates returns an instance of <code>ResourceMapping</code> explicitly 
  when asked for one. This is a more straightforward approach but the least desirable 
  as the model must have explicit knowledge of the adaptation to resources.</p>
<p>The implementation of the <code>ResourceMapping</code> subclass for a Java 
  package would look something like this.</p>
<pre style="background-color: rgb(204, 204, 255);">public class JavaPackageResourceMapping extends ResourceMapping {
   IPackageFragment package;
   ...
   public getModelObject() {
      return package;
   }
   public ResourceTraversals[] getTraversals(
             ResourceMappingContext context, 
             IProgressMonitor monitor) {
      return new ResourceTraversal[] { 
         new ResourceTraversal(
            new IResource[] { package.getCorrespondingResource() },
            IResource.DEPTH_ONE, IResource.NONE)
      }
   }
}</pre>
<p>This is a fairly straightforward mapping so the implementaion is not complex. 
  The complexity of the resource mapping implementation will, of course, vary 
  from model to model. The <code>EMFResourceMapping</code> example used above 
  is implemented in the example and it a much more complicated implementation.</p>
<h4>Contributing Menus to Resource Mappings</h4>
<p>Plug-ins that contribute extensions to adaptable extension points will have 
  to make two changes to support the new <code>ResourceMapping</code> APIs:</p>
<ol>
  <li>Update their plugin.xml files to change the objectClass of their adaptable 
    contributions to <code>ResourceMapping</code> (for those for which this is 
    appropriate).</li>
  <li>Update their actions to work on <code>ResourceMapping</code> instead of 
    <code>IResource</code> and respect the depth constraints provided in the traversals.</li>
  <li>(Optional) provide a <code>ResourceMappingContext</code> if they manage 
    remote resources (more on this <a href="#ResourceMappingContext">below</a>)</li>
</ol>
<p>First of all, plugins that add object contributions to <code>IResource</code> 
  (CVS, Search, Compare) can now add them to <code>ResourceMapping</code> instead, 
  if the action can apply to multiple resources. Here is an XML snipet that contributes 
  a menu action to objects that adapt to resource mappings:</p>
<pre style="background-color: rgb(204, 204, 255);">   &lt;extension<br>       point=&quot;org.eclipse.ui.popupMenus&quot;&gt;<br>    	&lt;objectContribution<br>            adaptable=&quot;true&quot;<br>            objectClass=&quot;org.eclipse.core.resources.mapping.ResourceMapping&quot;<br>            id=&quot;org.eclipse.example.library.ResourceMappingContributions&quot;&gt;<br>         &lt;action<br>               label=&quot;Show Resource Mappings&quot;<br>               class=&quot;org.eclipse.example.library.contributions.ShowResourceMappingsAction&quot;<br>               menubarPath=&quot;additions&quot;<br>               id=&quot;org.eclipse.example.library.showMappings&quot;/&gt;         <br>      	&lt;/objectContribution&gt;<br>   &lt;/extension&gt;</pre>
<p>Contributions to <code>ResourceMapping</code> will automatically apply to objects 
  that adapt to <code>IResource</code>. This transitive association is handled 
  by the Workbench.</p>
<p>Filtering of the contributions to resource mappings can be done using action 
  filters or expressions. An expression for filtering by project persistant property 
  has been added to allow repository providers to have their menus appear on projects 
  that are mapped to their repositories.</p>
<pre style="background-color: rgb(204, 204, 255);">   &lt;extension<br>       point=&quot;org.eclipse.ui.popupMenus&quot;&gt;<br>      &lt;objectContribution<br>            objectClass=&quot;org.eclipse.core.resources.mapping.ResourceMapping&quot;<br>            adaptable=&quot;true&quot;<br>            id=&quot;org.eclipse.team.ccvs.ui.ResourceMapperContributions&quot;&gt;<br>		 &lt;enablement&gt;<br>           &lt;adapt type=&quot;org.eclipse.core.resources.mapping.ResourceMapping&quot;&gt;<br>              &lt;test 
                 property=&quot;org.eclipse.ui.ide.projectPersistentProperty&quot; 
                 args=&quot;org.eclipse.team.core.repository=org.eclipse.team.cvs.core.cvsnature&quot; /&gt;<br>           &lt;/adapt&gt;<br>         &lt;/enablement&gt;<br>         &lt;action<br>               label=&quot;%UpdateAction.label&quot;<br>               definitionId=&quot;org.eclipse.team.cvs.ui.update&quot;<br>               class=&quot;org.eclipse.team.internal.ccvs.ui.actions.UpdateAction&quot;<br>               tooltip=&quot;%UpdateAction.tooltip&quot;<br>               menubarPath=&quot;team.main/group2&quot;<br>               id=&quot;org.eclipse.team.cvs.ui.update&quot;&gt;<br>         &lt;/action&gt;
         ...<br>      	&lt;/objectContribution&gt;<br>   &lt;/extension&gt;</pre>
<p>Actions that have been contributed to the <code>ResourceMapping</code> class 
  will be given a selection that contains one or more <code>ResourceMappings</code>. 
  It is the actions responsibility to translate the resource mapping into a set 
  of resources to be operated on. This can be done by calling <code>getTraversals</code> 
  to get the traversals of the mapping. Traversals are used to allow the clients 
  of the traversal to optimize their operations based on the depth of the resources 
  being traversed. A client may traverse the resource manually or may use the 
  resource and the depth as input into an operation that the action delegates 
  to do the work. As an example, if the user performs a CVS update on a java package 
  and the java package resource mapping maps to a folder of depth one, CVS would 
  issue an appropriat command (&quot;cvs update -l&quot; for those who are curious) 
  which would perform a shallow update on the folder the pakcage represents.</p>
<h3><a name="ResourceMappingContext"></a>Resource Mapping Context</h3>
<p>One of the advantages of a Resouce Mapping API is that it allows plug-ins to 
  implement any operations they desire in terms of resource mappings (e.g. CVS 
  update, CVS commit, CVS tag, dirty decoration, etc.). However, the API that 
  has been introduced so far deals only with the local state of the model. When 
  working with a model that may be shared between developers, you end up in a 
  situation where the remote state of the model (i.e. the state of the model that 
  another user has checked-in to the repository) may differ from the state in 
  the workspace. If you performed a CVS update, you would want the local state 
  of the model to match the remote state even if it meant that additional files 
  needed to be included or some files needed to be removed.</p>
<p>This is not an issue for some logical models. For instance, a java package 
  is a container visited to a depth of one, regardless of the remote state of 
  the model. Given this, a repository provider can easily determine that outgoing 
  deletions should be included when committing or that incoming additions should 
  be included when updating. However, the resources that constitute some logical 
  models may change over time. For instance, the resources that constitute a model 
  element may depend of the contents of a manifest file (or some other similar 
  mechanism). In order for the resource mapping to return the proper traversal, 
  it must access the remote contents of the manifest file (if it differes from 
  the local contents) in order to see if there are additional resources that need 
  to be included. These additional resources may not exist in the workspace but 
  the repository provider would know how to make sure they did when the selected 
  action was performed.</p>
<p>In order to support these more complex models, a <code>ResourceMappingContext</code> 
  can be passed to the <code>ResourceMapping#getTraversals</code> method. When 
  a context is provided, the mapping can use it to ensure that all the necessary 
  resources are included in the traversal. If a context is not provided, the mapping 
  can assume that only the local state is of interest. </p>
<h4>When does a ResourceMapping need to worry about the ResourceMappingContext?</h4>
<p>A <code>ResourceMapping</code> need only worry about a context supplied to 
  the <code>getTraversals</code> method in cases were the resources that make 
  up a model change over time and the relationship between the model and resources 
  cannot be described by a simple traversal that is gauranteed to encompass those 
  resources (and only those resources) that consitute the model. For example, 
  although the resources of a Java package may change over time, the package can 
  be described as a folder of depth of one so a resource mapping for java packages 
  would not ned to make use of the resource mapping context. </p>
<p>As a more complicated example, consider an HTML file that contains several 
  images. Let's make the assumption that any images references from an HTML file 
  are part of the model of that file. When updating the local contents of the 
  HTML file from a repository, the user would expect that any new images would 
  be included. The <code>getTraversals</code> method for a <code>ResourceMapping</code> 
  for the HTML file model would look something like this:</p>
<pre style="background-color: rgb(204, 204, 255);">public class HTMLResourceMapping extends ResourceMapping {
   private HTMLFile htmlFile;
   getTraversals(ResourceMappingContext context, IPorgressMonitor monitor) {
      IResource[] resources = htmlFile.getResources();
      if (context != null) {
         // Look for any additional resources on the server
         IFile file = htmlFile.getFile();
         if (context.contentDiffers(file, monitor) {
            IStorage storage = context.fetchContents(file, monitor);
            IResource[] additionalResources = getReferences(storage.getContents());
            resources = combine(resources, additionalResources);

         }
      }
      return new ResourceTraversal(resources, IResource.DEPTH_ZERO);

   }<br>}</pre>
<h4>When does a client need to provide a ResourceMappingContext?</h4>
<p>Any client that is providing the ability of sharing workspace resources through 
  a repository and is supporting ResourceMappings should provide an appropriate 
  context for determining the relevant remote state of the model resources. The 
  context provides three basic quieries:</p>
<ul>
  <li>Does the local contents differ from the remote contents</li>
  <li>What are the remote contents of a file</li>
  <li>What are the remote memebers of a folder</li>
</ul>
<p>The answer to the first question above depends on the type of operation that 
  is being performed:</p>
<ul>
  <li>When checking in a resource, the context would consider that a file's contents 
    differ if the local contents have been modified since the last check-in.</li>
  <li>When updating a resource, the context would consider that a file's contents 
    differ if the remote contents have been modified since the users last update.</li>
  <li>When replacing a resource, the context would consider that a file's contents 
    differ if either the the local or remote contents have changed since the last 
    synchronization.</li>
</ul>
<p>The Eclipse Team API includes a <code>Subcriber</code> class that defines an 
  API for providing the synchronization state between the local workspace and 
  a remote server. A <code>SubscriberResourceMappingContext</code> has been created 
  that uses a <code>Subscriber</code> to access the necessary remote state. Clients 
  that have a <code>Subscriber</code> do not need to do any additional work to 
  get a resource mapping context.</p>
<h2>How this will affect existing plug-ins</h2>
<p>Existing plugins do not need to change at all unless they want to take advantage 
  of the new API. For plugins that provide logical modes, it may be worthwhile 
  for them to adapt their model objects to <code>ResourceMappings</code>. Of course, 
  this is only a benefit when combined with a repository provider implementation 
  that contributes at last some of it's actions to resource mappings.</p>
<span style="font-weight: bold;"></span>
<h2>Open Issues</h2>
<p>The following issues would need to be addressed for this solutions.</p>
<ul>
  <li> Plugins that add object contributions will have to modify their actions 
    to handle logical resources. There should be some standard UI components for 
    showing the mappings. For instance you could show the logical model at the 
    top and in a details part the physical files/folders that will be affected 
    by the operation.</li>
  <li>Would it be possible to add a workbench adapter to specific implementations 
    IModelElement in order to get an image and label for a model element?</li>
  <li>Can the user benefit from resource mappings in cases where the repository 
    provider isn't mapping aware?</li>
  <li>What about reposiory providers that cannot provide a remote mapping context?</li>
  <li>What should a model provider do if they canno reliably determine the remote 
    model state? </li>
  <li>Need to reference the example<br>
  </li>
</ul>
</body>
</html>