blob: 3b065ff70641d71eca2242009137ad3bc9f4070a [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<table width="100%" cellpadding="2" cellspacing="5" border="0">
<tbody>
<tr>
<td bgcolor="#0080c0" valign="top" align="left"> <b><font
face="Arial,Helvetica" color="#ffffff"> Eclipse 3.1 - Plan item</font></b>
</td>
</tr>
</tbody>
</table>
<h1>Support Logical Resources</h1>
This document outlines the state of the Eclipse Platform <strong>Support
Logical Resources</strong> plan item. Interested parties should review
this document and verify that their use cases are reflected in the
requirements then later that the solution provided satisfies their
needs. Feedback is strongly encouraged and may be provided on the
platform-vcm-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.
<p class="MsoNormal">This is the plan item:</p>
<blockquote>
<p>"<em>The Eclipse Platform supports a strong physical view of
projects, files, and folders in the workspace. However, there are many
situations where a physical view is not the most salient or useful for
many purposes. In some cases, multiple distinct objects happen to be
stored in a single file, like an archive. Conversely, in other cases,
something that is logically a single object is stored across multiple
files. This discrepancy between logical and physical creates problems
for common operations such as searching, comparing, and versioning,
which need to work in the physical realm. Eclipse should support some
way of mapping between a logical view and the physical organization of
files on disk.</em>"</p>
<p>Last Modified: July 2nd, 2003</p>
</blockquote>
<h1>Motivation</h1>
<p>By definition Eclipse supports logical resources. It's a "an open
extensible IDE for anything and nothing in particular". The
applications that are built with it can be tailored to a particular
problem domain and the workbench extensions can be used to provide
support for any logical model. What Eclipse really doesn't support is
integrating tools at the logical model. In order to integrate two
plugins into Eclipse either the two plugins have to know about each
other, or both plugins have to depend on some common plugin. While the
first option is satisfactory for a few cases, the second case is the
most common and the most problematic. To illustrate, the Eclipse SDK
contains several plugins that are based on the Resources plugin (e.g.
Team, Search, Compare, JDT). When an application is packaged based on
the SDK, because the plugins in the SDK are resource based that is the
common integration point between plug-ins.<br>
</p>
<p>As you will see later, even the users of the SDK (JDT+CVS+Resources)
can observe some of the problems associated with the lack of support
for logical resources and the implicit mapping to physical resources.
The lack of a logical integration point causes the co-existance of
plugins in Eclipse to be error prone for the user. The next sections
will examine the relationships between logical and physical resources
and outline the visible problems with Eclipse 3.0. </p>
<h2>Existing Bugs</h2>
<p>Bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=32582">32582</a>
logical to physical mapping problem , 1 model element = 2 Files problem<br>
Bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=3979">3979</a>
[CVS Decorator] show version info works incorrectly for sub packages
(1GFDIEB)</p>
<h2>Logical Resources Defined<br>
</h2>
<p>Whereas logical resources are elements of the application that model
the data/processes of a particular problem domain, the physical
resources are the file system resources (e.g. files and folders) into
which an application will eventually transform their application model
for storage. Applications that don't use file system resources are not
being considered as part of this plan item. For example, an application
that stores it's application data directly into a database.</p>
<p>The following table enumerates concrete examples of how logical and
physical resources are used in current applications integrated into
Eclipse.</p>
<p><a name="#table1"></a>Table 1: Example logical to physical uses</p>
<table border="1" width="100%">
<tbody>
<tr>
<td width="23%">
<div align="center"><strong>Relationships</strong></div>
</td>
<td width="77%">
<div align="center"><strong>Examples</strong></div>
</td>
</tr>
<tr>
<td>
<p>logical (1) &lt;-&gt; (*) physical</p>
<p>one logical to many physical</p>
</td>
<td valign="top">
<p><a name="#1a"></a>(<strong>1a</strong>) EJB maps to several
physical files: (WSAD + XDE Tester). This is the most common case we
have found. </p>
<blockquote>
<p>/src/org/app/bean.java<br>
/src/org/app/beanr.java<br>
/src/org/app/beanlocal.java</p>
</blockquote>
<p><em>Note: If one of the logical resource's files was deleted
who would remember that the file used to exist and is an outgoing
deletion or that there is an incoming addition to the logical resource?</em></p>
<p><a name="#1b"></a>(<strong>1b</strong>) Composite Object
(logical) maps to several changed physical resources. (Rational XDE)</p>
<p><em>Note</em>: <em>With 1 to many relationship there is
always the complication that arises if the logical element maps to
files in an other project? This would cause many problems in the
current Team plugin.</em></p>
</td>
</tr>
<tr>
<td>
<p>logical (*) &lt;-&gt; (1) physical</p>
<p>many logical to one physical</p>
</td>
<td valign="top">
<p><a name="#2a"></a>(<strong>2a</strong>) Methods in a class map
to their containing class file. (JDT)</p>
<p><a name="#2b"></a>(<strong>2b</strong>) Archive files (zip,
jar) can be seen as a logical and the contents of the archive all map
to the same physical.(JTD + all)</p>
</td>
</tr>
<tr>
<td>
<p>logical (1) &lt;-&gt; (1) physical</p>
<p>one logical to one physical</p>
</td>
<td valign="top">
<p><a name="#3a"></a>(<strong>3a</strong>) A Java Package maps to
a folder but a package does not include sub folders (e.g. they are
shallow). (JDT)</p>
<p><a name="#3b"></a>(<strong>3b</strong>) A UML class maps to a
file. For example, in a UML application a class could be stored in a
single file called 'x435dsds.umlclass'. The reason it's a logical is
that the user of the application will never be concerned about the
actual file name or even the folder it's stored in. (XDE)</p>
</td>
</tr>
</tbody>
</table>
<h1>Complaints<br>
</h1>
<p>The following complaints are representative of bug reports and
requirements received from several Eclipse plug-in developers. <br>
</p>
<h2>Complaint 1: Not very adaptable</h2>
<p>Object contributions and decorators are key mechanisms for providing
rich integration between tools. Using object contributions and
adaptable objects, any plugin can provide actions and decorators that
will show in another plugin's view. </p>
<p>Since IResource is the lowest common integration class and is
strongly mapped to its physical storage as files and folders, the
integration point for actions and decorators cannot be the logical
types in the view. The actions will consequently use the adaptable type
from the selection to perform the action or the decorator the resource
from the getImage request.</p>
<p>Here is an example to illustrate the problem with the CVS plugin.
When running a CVS commit action in the packages view the action
doesn't know that the IFolder is a Java package and is a shallow
namespace. It will use the selection and traverse the selected
IContainer using IContainer.members() and commit all child resources.
This is the same when the CVS outgoing decorator is shown on a package.
It will reflect the deep outgoing state of the IContainer. This can
lead to unexpected behavior because the user expected the action to run
on the model that the action was displayed on.</p>
<p>Example object contribution for the CVS commit action:</p>
<pre>&lt;extension point="org.eclipse.ui.popupMenus"&gt;<br> &lt;objectContribution<br> objectClass="org.eclipse.core.resources.IResource"<br> adaptable="true"<br> id="org.eclipse.team.ccvs.ui.IResourceContributions"&gt;<br> &lt;filter<br> name="projectPersistentProperty"<br> value="org.eclipse.team.core.repository=org.eclipse.team.cvs.core.cvsnature"&gt;<br> &lt;/filter&gt;<br> &lt;action<br> label="Commit"<br> tooltip="Commit resource to CVS repository"<br> class="org.eclipse.team.internal.ccvs.ui.actions.CommitAction"<br> menubarPath="team.main/group3"<br> id="org.eclipse.team.ccvs.ui.commit"&gt;<br> &lt;/action&gt;<br> &lt;objectContribution&gt;<br>&lt;/extension&gt;<br></pre>
<p>Example code run in the commit action to calculate the resources to
commit:</p>
<pre>public static Object[] getSelectedAdaptables(ISelection selection) {<br> ArrayList result = null;<br> if (!selection.isEmpty()) {<br> result = new ArrayList();<br> Iterator elements = ((IStructuredSelection) selection).iterator();<br> while (elements.hasNext()) {<br> Object adapter = getAdapter(elements.next(), IResource.class);<br> if (c.isInstance(adapter)) {<br> result.add(adapter);<br> }<br> }<br> }<br> if (result != null &amp;&amp; !result.isEmpty()) {<br> return (Object[])result.toArray((Object[])Array.newInstance(IResource.class, result.size()));<br> }<br> return (Object[])Array.newInstance(IResource.class, 0);<br>}</pre>
<p>Example code for defining an IResource adaptable decorator:</p>
<pre>&lt;extension<br> point="org.eclipse.ui.decorators"&gt;<br> &lt;decorator objectClass="org.eclipse.core.resources.IResource"<br> adaptable="true"<br> label="%DecoratorStandard.name"<br> state="false"<br> lightweight= "true"<br> quadrant = "BOTTOM_RIGHT"<br> class="org.eclipse.team.internal.ccvs.ui.CVSLightweightDecorator"<br> id="org.eclipse.team.cvs.ui.decorator"&gt;<br> &lt;description&gt;<br> %DecoratorStandard.desc<br> &lt;/description&gt;<br> &lt;/decorator&gt;<br>&lt;/extension&gt;</pre>
<h2>Complaint 2: Decorators</h2>
<p>When the CVS decorator decorates a logical container in a view, the
desire is to decorate parents with the dirty indicator if one or more
of their logical children are dirty. To do this properly, the decorator
would need to query the dirty status of each of the logical children of
the container. This can be a costly operation as each child may itself
be a logical container. We have optimized the dirty decoration by
caching folder dirty states. This optimization becomes far more
complicated with logical models where the caching must be based on this
alternate model (i.e. the state must be cached for each model).</p>
<p> In addition, often decorators rely on&nbsp;IResource change events
to re-calculate some new state. In the case of a logical elements
representing several physical resources there is no easy way of
associated a IResource change event to its files and the actual logical
element.</p>
<h2>Complaint 3: Presentation of mixed logical models<br>
</h2>
<p>It would be nice to see the Java logical view in the Synchronize
view, in the navigator, or in dialogs contributed by other plug-ins
besides JDT. However, the entries in these views
may not be IResources so an IResource independent mapping mechanism
would be required. A workaround for this problem is demonstrated by the
Search plug-in which allows for plug-ins to integrate with other tools
by contributing domain specific pages. JDT contributes a JDT search
page to the view and shows logical Java elements. This solution however
doesn't allow showing mixed logical models in the same widget, which is
required in the Synchronize View and Navigator.<br>
</p>
Also if an action prompts the user, for example to add resources to
CVS, what icons and labels are used in the dialog? It would be nice to
show those that are most familiar to the user. <br>
<br>
There are two levels of logical model presentation:<br>
<ul>
<li>Need for full access to a logical model that would allow building
a dynamic UI. This would include mapping from an IResource to a logical
element.<br>
</li>
</ul>
<ul>
<li>Need name and icon for a logical element to display in simple
dialogs.<br>
</li>
</ul>
<h2>Complaint 4: Change Sets</h2>
<p>Consider a user's action as a logical change, for example, the user
renames a class using the JDT refactoring action. In the user's mind he
'renamed a class' and as a result there has been many other file
changes. Currently there is not way of capturing these logical actions
and associating the set of affected resources. This problem manifests
itself more in tools where almost every change to the model has side
effects.</p>
<h2>Complaint 5: Participating in operations</h2>
Some logical models may want to participate and even restrict the kinds
of operations are
allowed on theirs files. For example, if a logical element is composed
of three files, the users should not be allowed to move, or delete them
individually. In essence, a way of vetoing the move/rename, copy, or
delete would be useful to ensure a coherant logical model.<br>
<h2>Complaint 6: IResource based views in the IDE</h2>
There are several views in the workbench IDE that could be used by
logical models but are currently too tied to resources. For example,
the problems and tasks views have a resource column and works uniquely
on IResource markers. This means that if a logical model provides
problems and tasks the problems and tasks views cannot be used to show
the logical element instead of the file.<br>
<h2>Complaint 7: Merging can't consider all files related to a logical
element</h2>
When merging a logical element the repository may find a conflict in
one of the files that is part of the logical element. The repository
tool will typically fetch the revisions for the conflicting file so
that a comparison can be shown to the user. But since the repository
tool doesn't know that other files are part of the logical resource,
the comparison shown to the user doesn't have access to the correct
revisions of the other files. This is a problem because it then becomes
impossible to implement a comparison that has access to all the
revisions of the logical element's files.<br>
<h1>Discussion</h1>
<p>The above complaints form the community hint at a missing feature in
the Eclipse platform: there is a lack of a data modeling framework that
would allow information to be modelled independently from their binary
and storage locations. A common discussion in the community is the idea
that the resources plug-in should be generalized to become this generic
model, but in reality it wasn't designed as such and although it
contains common model services such as eventing and threading, it was
explicitly designed to model the file system. Changes to the resources
plug-in would be a major breaking API change and not acceptable to the
community. <br>
</p>
<p>There are however some alternatives. First, it is possible to solve
some of the above complaints without introducing a full featured data
model framework. Let's start by grouping the complaints:<br>
</p>
<span style="font-weight: bold;">Adaptables:<br>
</span>Complaint 1: Not very adaptable<br>
Complaint 2: Decorators<br>
Complaint 7: Merging can't consider files related to a logical element<br>
<p><span style="font-weight: bold;">Presentation of logical models:</span><br>
Complaint 6: IResource based views in the IDE<br>
Complaint 3: Presentation of mixed logical models<br>
</p>
<p><span style="font-weight: bold;">Logical Model Operations:</span><br>
Complaint 4: Change Sets<br>
Complaint 5: Participating in operations<br>
</p>
<h1>Possible Solution Approaches For Adaptables<br>
</h1>
<p>URL diagram<br>
Example logical model provider code<br>
Example repository provider actions/objectContribution<br>
Example merge case<br>
Example decorator<br>
Example model context<br>
</p>
<p>======<br>
</p>
<p>There are basically two approaches to solving the problems discussed
above:</p>
<ul>
<li>A logical model API that can be used by clients (such as
repository providers) in order to determine what physical resources
constitute model elements.</li>
<li>A repository provider API that would allow model providers to
perform repository operations on their constituant resources.</li>
</ul>
<p>At the present time, the second approach, by itself, is not viable
due to its complexity. There is a JSR (JSR 147) that defines such an
ineterface but it is not yet finalized and there is not timetable for
when it will be. However, to do the first approach properly will
require some repository provider API. This is discussed in the
following section which propese a solution.</p>
<h2> Logical Model Traversal API</h2>
<p>One possible solution is to introduce a logical model element API
that can be the basis for integration between plugins. This solution
attempts to solve the most common uses described in <a href="#table1">Table1</a>,
namely examples <a href="#1a">1a</a>, <a href="1b">1b</a> and <a
href="3a">3a</a>. The <a
href="http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-ui-home/navigator-proposal/general_purpose_navigator_proposal.html">generic
navigator</a> plan item should address the <a href="2b">2b</a> and <a
href="3b">3b</a> examples by providing extensions that would allow a
logical model to be available to other plugins for display purposes.
Finally, <a href="2a">2a</a> is currently solved with the existing <code>IResource</code>
adapter mechanism.</p>
<p>Naturally another possible solution would be to change <code>IResource</code>
to not be analogous to file system resources. However this scope of
change is beyond the 3.0 timeframe and would cause, in my opinion,
non-justifiable breaking changes to all plugins.</p>
<h3>IlModelElement</h3>
<p>This solution involves adding an interface to the Resources plugin
that maps logical elements to physical ones. The interface is purposely
simple with logical model manipulations ommitted. A client can't use
this interface to display logical models or gain any interesting
additional knowledge about it. In fact, the only way that a plugin will
be able to gain access to the model for those purposes, would be via
the navigator extensions proposed in the <a
href="http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-ui-home/navigator-proposal/general_purpose_navigator_proposal.html">generic
nagivator</a> plan item.</p>
<p>Current plugins that add object contributions to <code>IResource</code>
(CVS, Search, Compare) would have to also add them to <code>IModelElement</code>
and honour the biddings provided by the logical resource. Moreover, the
plugins that adapted to <code>IResource</code> to these object
contributions shown in the context menu should no longer adapt the <code>IResource</code>
and instead implement <code>IModelElement</code> (this could be
simplified by adding a tag to the objectConribution XML that indicates
that it can be used with <code>IResource</code> or <code>IModelElement</code>).</p>
<blockquote>
<pre>/**<br> * This interface defines an element of an application that models the<br> * data/processes of a particular problem domain. This purpose of this interface<br> * is to support the transformation of the application model into its underlying<br> * file system resources for the purposes of reconciling the model with versions<br> * of the model stored in a repository. Hence, this interface provides the<br> * bridge between a logical element and the physical resource(s) into which it<br> * is stored but does not provide more comprehensive model access or<br> * manipulations.<br> * <br> * @see IResource<br> */<br>public interface IModelElement {<br> <br> /**<br> * Returns the project which contains this model element. This is a resource<br> * handle operation; neither the element nor the resulting project need<br> * exist. Model elements may not span multiple projects. In other words, all<br> * physical resources that constitute a logical resource are located in the<br> * same project.<br> * <br> * @return the project handle<br> */<br> public IProject getProject();<br> <br> /**<br> * Returns one or more traversals that can be used to access all the<br> * physical resources that constitute the logical resource. A traversal is<br> * simply a set of resources and the depth to which they are to be<br> * traversed. This method returns an array of traversals in order to provide<br> * flexibility in describing the traversals that constitute a model element.<br> * A depth is included to allow the clients of this interface (most likely<br> * repository providers) an opportunity to optimize the operation and also<br> * ensure that resources that were or have become members of the model<br> * element are included in the operation.<br> * <br> * Implementors of this interface should ensure, as much as possible, that<br> * all resources that are or may be members of the model element are<br> * included. For instance, a model element should return the same list of<br> * resources regardless of the existance of the files on the file system.<br> * For example, if a logical resource called "form" maps to "/p1/form.xml"<br> * and "/p1/form.java" then whether form.xml or form.java existed, they<br> * should be returned by this method.<br> * <br> * In some cases, it may not be possible for a model element to know all the<br> * resources that may consitite the element without accessing the state of<br> * the model element in another location (e.g. a repository). This method is<br> * provided with a context which, when provided, gives access to<br> * the members of correcponding remote containers and the contenst of<br> * corresponding remote files. This gives the model element the opportunity<br> * to deduce what additional resources should be included in the traversal.<br> * <br> * @param context gives access to the state of<br> * remote resources that correspond to local resources for the<br> * purpose of determining traversals that adequately cover the<br> * model element resources given the state of the model element<br> * in another location. A null may be provided, in<br> * which case the implementor can assume that only the local<br> * resources are of interest to the client.<br> * @param monitor a progress monitor<br> * @return a set of traversals that cover the resources that constitute the<br> * model element<br> */<br> public ITraversal[] getTraversals(IModelContext context,<br> IProgressMonitor monitor) throws CoreException;<br>}</pre>
</blockquote>
<h3>ITraversal</h3>
<p>A logical model element can be made up of one or more traversals
that define the physical resources that make up the model element.
Traversals are used to allow the clients of the traversal to optimize
their operations based on the depth of the resources being traversed.</p>
<blockquote>
<pre>/** <br> * A model element traversal is simply a set of resources and<br> * the depth to which each are to be traversed. A set of traversals<br> * is used to describe the resources that constitute a model element.<br> *<br> * @see org.eclipse.core.resources.IResource<br> * @see org.eclipse.core.resources.model.IModelElement<br> */<br>public interface ITraversal {<br> <br> /**<br> * Returns the project which contains the resources that<br> * make up this taversal.<br> * <br> * @return the project handle<br> */<br> public IProject getProject();<br> <br> /**<br> * Returns the file system resource(s) for this traversal. <br> * The returned resources must be contained within the same project <br> * and need not exist in the local file system.<br> * <br> * The traversal of the returned resources should be done considering<br> * the flag returned by getDepth. If a resource returned by a <br> * traversal is a file, it should always be visited. If a resource of a traversal<br> * is a folder then files contained in the folder can only be visited if the folder is<br> * IResource.DEPTH_ONE or IResource.DEPTH_INFINITE. <br> * Child folders should only be visited if the depth is IResource.DEPTH_INFINITE.<br> */<br> public IResource[] getResources();<br> <br> /**<br> * Return the depth to which the resources should be traversed.<br> * @return the depth to which the physical resources are to be traversed<br> * (one of IResource.DEPTH_ZERO, IResource.DEPTH_ONE or IResource.DEPTH_INFINITE)<br> */<br> public int getDepth();<br>}</pre>
</blockquote>
<p>For some model elements, simple traversals can be used to describe
the element. For instance, here is an example traversal that represents
a Java package.</p>
<blockquote>
<pre>/**<br> * An example traversal for a Java package<br> */<br>public class JavaPackageTraversal implements ITraversal {<br> IContainer javaPackage;<br> public JavaPackageTraversal(IContainer javaPackage) {<br> this.javaPackage = javaPackage;<br> }<br> public IProject getProject() {<br> return javaPackage.getProject();<br> }<br> public IResource[] getResources() {<br> return new IResource[] { javaPackage };<br> }<br> public int getDepth() {<br> return IResource.DEPTH_ONE;<br> }<br>}</pre>
</blockquote>
<p>The next example class shows a traversal for a fixed set of files.
The chosen example is for the data files that define the properties of
a plugin in Eclipse. The same files are always returned even if they
don't exist locally. It is up to the client of the interface in this
case to decide how to handle the files that don't exist locally. If the
client is a repository and the operation is an update to fetch the
latest contents from the server, then the repository provider would
fetch the files from the server if they now esist there or ignore them
if they don't exist either locally or remotely.</p>
<blockquote>
<pre>/**<br> * An example of a fixed traversal that always includes<br> * a certain set of files even if they don't exist <br> * locally<br> */<br>public class PluginDataTraversal implements ITraversal {<br> IProject pluginProject;<br> public PluginDataTraversal(IProject project) {<br> this.pluginProject = project;<br> }<br> public IProject getProject() {<br> return pluginProject;<br> }<br> public IResource[] getResources() {<br> return new IResource[] {<br> pluginProject.getFile(new Path("plugin.xml")),<br> pluginProject.getFile(new Path("plugin.properties")),<br> pluginProject.getFile(new Path("build.properties")),<br> pluginProject.getFile(new Path("META-INF/MANIFEST.MF"))<br> };<br> }<br> public int getDepth() {<br> return IResource.DEPTH_ZERO;<br> }<br>}</pre>
</blockquote>
<p> Assuming that the plugin data consists of the above mentioned files
and the contents of the schema directory, the model element class for a
plugin's data model could be the following:</p>
<blockquote>
<pre>/**<br> * A plugin model element<br> */<br>public class PluginModel implements IModelElement {<br> IProject pluginProject;<br> public IProject getProject() {<br> return pluginProject;<br> }<br> public ITraversal[] getTraversals(ITraversalContext context,<br> IProgressMonitor monitor) throws CoreException {<br> return new ITraversal[] {<br> new PluginDataTraversal(pluginProject),<br> new ITraversal() {<br> public IProject getProject() {<br> return pluginProject;<br> }<br> public IResource[] getResources() {<br> return new IResource[] {<br> pluginProject.getFolder("schema")<br> };<br> }<br> // Traverse the folder deeply to include all children<br> public int getDepth() {<br> return IResource.DEPTH_INFINITE;<br> }<br> }<br> };<br> }<br>}</pre>
</blockquote>
<h3>IModelContext</h3>
<p>One of the advantages of a logical model traversal API is that it
allows the repository provider to implement any operations they desire
in terms of logical resources (e.g. update, commit, tag, dirty
decoration, etc.). However, the context of the operation may imply that
resources that don't exist locally should be included in the operation.
This is not a problem for some logical models. For instance, a java
package is a container visited to a depth of one. Also, the plugin
example knows all the files that vould potentially be involved, even if
they don't exist locally. 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.</p>
<p>However, properly determining the set of traversals that adequately
cover a model element gets more complicated if the resources that
constitute the element depend of the contents of a manifest file (or
some other similar mechanism) and may change over time. In this case,
it is possible that the model element could access the contents of the
manifest file as contained in the remote location. Given this ability,
the model element provider is provided with enough context about the
operation to the logical model element so a set of traversal can be
returned that adequately cover all resources that constitute the model
element. </p>
<p>This has led to the definition of the following <code>IModelContext</code>
interface. </p>
<blockquote>
<pre>/**<br> * A model context provides a model element with a view of the remote state<br> * of a local resource as it relates to a repository operation that is in<br> * progress. A repository provider can pass an instance of this interface to a<br> * model element when obtaining a set of traversals for a model element. This<br> * allows the model element to query the remote state of a resource in order to<br> * determine if there are resources that exist remotely but do not exist locally<br> * that should be included in the traversal.<br> */<br>public interface IModelContext {<br> <br> /**<br> * Return whether the contents of the corresponding remote differs from the<br> * content of the local file. This can be used by clients to determine if<br> * they nee to fetch the remote contents in order to determine if the<br> * resources that constitute the model element are different in another<br> * location.<br> * <br> * @param file the local file<br> * @param monitor a progress monitor<br> * @return whether the contents of the corresponding remote differs from the<br> * content of the local file<br> * @throws CoreException if this method fails. Reasons include:<br> * - The corresponding remote resource does not exist (status<br> * code will be IResourceStatus.REMOTE_DOES_NOT_EXIST).<br> * - The corresponding remote resource is not a container<br> * (status code will be IResourceStatus.REMOTE_WRONG_TYPE).<br> * - The server communications failed (status code will be<br> * IResourceStatus.REMOTE_COMMUNICATION_FAILURE).<br> */<br> public boolean contentDiffers(IFile file, IProgressMonitor monitor)<br> throws CoreException;<br> <br> /**<br> * Returns an instance of IStorage in order to allow the<br> * caller to access the contents of the remote that corresponds to the given<br> * local resource. The provided local file handle need not exist locally. A<br> * exception is thrown if the corresponding remote resource does not exist<br> * or is not a file.<br> * <br> * This method may be long running as a server may need to be contacted to<br> * obtain the contents of the file.<br> * <br> * @param file the local file<br> * @param monitor a progress monitor<br> * @return a storage that provides access to the contents of the local<br> * resource's corresponding remote resource<br> * @throws CoreException if this method fails. Reasons include:<br> * - The corresponding remote resource does not exist (status<br> * code will beIResourceStatus.REMOTE_DOES_NOT_EXIST).<br> * - The corresponding remote resource is not a file (status<br> * code will be IResourceStatus.REMOTE_WRONG_TYPE).<br> * - The server communications failed (status code will be<br> * IResourceStatus.REMOTE_COMMUNICATION_FAILURE).<br> */<br> public IStorage fetchContents(IFile file, IProgressMonitor monitor)<br> throws CoreException;<br><br> /**<br> * Returns the list of member resources whose corresponding remote resources<br> * are members of the corresponding remote resource of the given local<br> * container. The container need not exist locally and the result may<br> * include entries that do not exist locally and may not include all local<br> * children. An empty list is returned if the remote resource which<br> * corresponds to the container is empty. An exception is thrown if the<br> * corresponding remote does not exist or is not capable of having members.<br> * <br> * This method may be long running as a server may need to be contacted to<br> * obtain the members of the containers corresponding remote resource.<br> * <br> * @param container the local container<br> * @param monitor a progress monitor<br> * @return a list of member resources whose corresponding remote resources<br> * are members of the remote counterpart of the given container<br> * @throws CoreException if this method fails. Reasons include: <br> * - The corresponding remote resource does not exist (status<br> * code will be IResourceStatus.REMOTE_DOES_NOT_EXIST).<br> * - The corresponding remote resource is not a container<br> * (status code will be IResourceStatus.REMOTE_WRONG_TYPE).<br> * - The server communications failed (status code will be<br> * IResourceStatus.REMOTE_COMMUNICATION_FAILURE).<br> */<br> public IResource[] fetchMembers(IContainer container,<br> IProgressMonitor monitor) throws CoreException;<br>}</pre>
</blockquote>
<p>Although this can be thought of as a repository provider API, it
bypasses the complexity by allowing the repository provider to
implement the interface in a maner specific to the operation being
performed. For instance, for a commit, the repository provider would
provide the contents of files that define the base of a manifest file.
In other words, the contents of the file would match the contents
before the user modified the model element. This would allow for the
inclusion of any outgoing deletions. For an update, the repository
provider would provide access to the contents of the file in the
repository.</p>
<h3>Issues</h3>
<p>This section is devided into two sections. Client isses which
indicate what isses the implementators of the above mentioned
interfaces face, and Eclipse Platform issues that will need to be
addressed when and if the solution is implemented.</p>
<h4>Client Issues</h4>
<p>There are uncertainties for this solution:</p>
<ul>
<li>Can all repository providers reasonably implement the
ITraversalContext for use by the model elements</li>
<li>Can the model elements implement the code that makes use of this
context to determine what additional resources make up the model</li>
</ul>
<p>Either of these efforts may be non-trivial depending on the
structure and functionality of the repository provider's or model
provider's Eclispse intergration. </p>
<h4>Eclipse Platform Issues</h4>
<p>The following issues would need to be addressed for this solutions</p>
<ol>
<li>ObjectContributions have to be duplicated in the plugins that
would like to provide both contributions for <code>IResource</code>
and <code>ILogicalResource</code>. </li>
<ul>
<li>This could be simplified by adding support to tag an
objectContribution for use with both interfaces</li>
</ul>
<li>Logical classes (e.g. java model, UML) have to implement the
interface instead of adapting to it. This is a limitation of the
current objectContribution story in the workbench. </li>
<ul>
<li>Again, this could be circumvented with support in the UI that
does the same magic for <code>ILogicalResource</code> that is done for
<code>IResource</code></li>
</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>
</ol>
</body>
</html>