| <!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) <-> (*) 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 (*) <-> (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) <-> (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><extension point="org.eclipse.ui.popupMenus"><br> <objectContribution<br> objectClass="org.eclipse.core.resources.IResource"<br> adaptable="true"<br> id="org.eclipse.team.ccvs.ui.IResourceContributions"><br> <filter<br> name="projectPersistentProperty"<br> value="org.eclipse.team.core.repository=org.eclipse.team.cvs.core.cvsnature"><br> </filter><br> <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"><br> </action><br> <objectContribution><br></extension><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 && !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><extension<br> point="org.eclipse.ui.decorators"><br> <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"><br> <description><br> %DecoratorStandard.desc<br> </description><br> </decorator><br></extension></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 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> |