KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > core > synchronize > SyncInfo


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.team.core.synchronize;
12
13 import org.eclipse.core.resources.IResource;
14 import org.eclipse.core.runtime.Assert;
15 import org.eclipse.core.runtime.IAdaptable;
16 import org.eclipse.osgi.util.NLS;
17 import org.eclipse.team.core.TeamException;
18 import org.eclipse.team.core.variants.IResourceVariant;
19 import org.eclipse.team.core.variants.IResourceVariantComparator;
20 import org.eclipse.team.internal.core.Messages;
21
22 /**
23  * Describes the synchronization of a <b>local</b> resource
24  * relative to a <b>remote</b> resource variant. There are two
25  * types of comparison: two-way and three-way.
26  * The {@link IResourceVariantComparator} is used to decide which
27  * comparison type to use.
28  * </p>
29  * <p>
30  * For two-way comparisons, a <code>SyncInfo</code> node has a change
31  * type. This will be one of IN-SYNC, ADDITION, DELETION or CHANGE determined
32  * in the following manner.
33  * <ul>
34  * <li>A resource is considered an ADDITION if it exists locally and there is no remote.
35  * <li>A resource is considered an DELETION if it does not exists locally and there is remote.
36  * <li>A resource is considered a CHANGE if both the local and remote exist but the
37  * comparator indicates that they differ. The comparator may be comparing contents or
38  * timestamps or some other resource state.
39  * <li>A resource is considered IN_SYNC in all other cases.
40  * </ul>
41  * </p><p>
42  * For three-way comparisons, the sync info node has a direction as well as a change
43  * type. The direction is one of INCOMING, OUTGOING or CONFLICTING. The comparison
44  * of the local and remote resources with a <b>base</b> resource is used to determine
45  * the direction of the change.
46  * <ul>
47  * <li>Differences between the base and local resources
48  * are classified as <b>outgoing changes</b>; if there is
49  * a difference, the local resource is considered the
50  * <b>outgoing resource</b>.
51  * <li>Differences between the base and remote resources
52  * are classified as <b>incoming changes</b>; if there is
53  * a difference, the remote resource is considered the
54  * <b>incoming resource</b>.
55  * <li>If there are both incoming and outgoing changes, the resource
56  * is considered a <b>conflicting change</b>.
57  * Again, the comparison of resources is done using the variant comparator provided
58  * when the sync info was created.
59  * </p>
60  * @since 3.0
61  */

62 public class SyncInfo implements IAdaptable {
63     
64     /*====================================================================
65      * Constants defining synchronization types:
66      *====================================================================*/

67
68     /**
69      * Sync constant (value 0) indicating element is in sync.
70      */

71     public static final int IN_SYNC = 0;
72     
73     /**
74      * Sync constant (value 1) indicating that one side was added.
75      */

76     public static final int ADDITION = 1;
77     
78     /**
79      * Sync constant (value 2) indicating that one side was deleted.
80      */

81     public static final int DELETION = 2;
82     
83     /**
84      * Sync constant (value 3) indicating that one side was changed.
85      */

86     public static final int CHANGE = 3;
87
88     /**
89      * Bit mask for extracting the change type.
90      */

91     public static final int CHANGE_MASK = CHANGE;
92     
93     /*====================================================================
94      * Constants defining synchronization direction:
95      *====================================================================*/

96     
97     /**
98      * Sync constant (value 4) indicating a change to the local resource.
99      */

100     public static final int OUTGOING = 4;
101     
102     /**
103      * Sync constant (value 8) indicating a change to the remote resource.
104      */

105     public static final int INCOMING = 8;
106     
107     /**
108      * Sync constant (value 12) indicating a change to both the remote and local resources.
109      */

110     public static final int CONFLICTING = 12;
111     
112     /**
113      * Bit mask for extracting the synchronization direction.
114      */

115     public static final int DIRECTION_MASK = CONFLICTING;
116     
117     /*====================================================================
118      * Constants defining synchronization conflict types:
119      *====================================================================*/

120     
121     /**
122      * Sync constant (value 16) indication that both the local and remote resources have changed
123      * relative to the base but their contents are the same.
124      */

125     public static final int PSEUDO_CONFLICT = 16;
126     
127     /**
128      * Sync constant (value 32) indicating that both the local and remote resources have changed
129      * relative to the base but their content changes do not conflict (e.g. source file changes on different
130      * lines). These conflicts could be merged automatically.
131      */

132     public static final int AUTOMERGE_CONFLICT = 32;
133     
134     /**
135      * Sync constant (value 64) indicating that both the local and remote resources have changed relative
136      * to the base and their content changes conflict (e.g. local and remote resource have changes on
137      * same lines). These conflicts can only be correctly resolved by the user.
138      */

139     public static final int MANUAL_CONFLICT = 64;
140     
141     /*====================================================================
142      * Members:
143      *====================================================================*/

144      private IResource local;
145      private IResourceVariant base;
146      private IResourceVariant remote;
147      private IResourceVariantComparator comparator;
148      
149      private int syncKind;
150     
151      /**
152       * Construct a sync info object.
153       * @param local the local resource. Must be non-null but may not exist.
154       * @param base the base resource variant or <code>null</code>
155       * @param remote the remote resource variant or <code>null</code>
156       * @param comparator the comparator used to determine if resources differ
157       */

158     public SyncInfo(IResource local, IResourceVariant base, IResourceVariant remote, IResourceVariantComparator comparator) {
159         Assert.isNotNull(local);
160         Assert.isNotNull(comparator);
161         this.local = local;
162         this.base = base;
163         this.remote = remote;
164         this.comparator = comparator;
165     }
166     
167     /**
168      * Returns the state of the local resource. Note that the
169      * resource may or may not exist.
170      *
171      * @return a resource
172      */

173     public IResource getLocal() {
174         return local;
175     }
176     
177     /**
178      * Returns the content identifier for the local resource or <code>null</code> if
179      * it doesn't have one. For example, in CVS this would be the revision number.
180      *
181      * @return String that could be displayed to the user to identify this resource.
182      */

183     public String JavaDoc getLocalContentIdentifier() {
184         return null;
185     }
186         
187     /**
188      * Returns the remote resource handle for the base resource,
189      * or <code>null</code> if the base resource does not exist.
190      * <p>
191      * [Note: The type of the common resource may be different from the types
192      * of the local and remote resources.
193      * ]
194      * </p>
195      * @return a remote resource handle, or <code>null</code>
196      */

197     public IResourceVariant getBase() {
198         return base;
199     }
200     
201     /**
202      * Returns the handle for the remote resource,
203      * or <code>null</code> if the remote resource does not exist.
204      * <p>
205      * [Note: The type of the remote resource may be different from the types
206      * of the local and common resources.
207      * ]
208      * </p>
209      * @return a remote resource handle, or <code>null</code>
210      */

211     public IResourceVariant getRemote() {
212         return remote;
213     }
214     
215     /**
216      * Returns the comparator that is used to determine the
217      * kind of this sync node.
218      *
219      * @return the comparator that is used to determine the
220      * kind of this sync node.
221      */

222     public IResourceVariantComparator getComparator() {
223         return comparator;
224     }
225     
226     /**
227      * Returns the kind of synchronization for this node.
228      *
229      * @return the kind of synchronization for this node.
230      */

231     public int getKind() {
232         return syncKind;
233     }
234     
235     /**
236      * Helper method that returns whether the given kind represents
237      * an in-sync resource.
238      *
239      * @param kind the kind of a <code>SyncInfo</code>
240      * @return whether the kind is <code>IN_SYNC</code>.
241      */

242     static public boolean isInSync(int kind) {
243         return kind == IN_SYNC;
244     }
245     
246     /**
247      * Helper method to return the direction portion
248      * of the given kind. The resulting value
249      * can be compared directly with the direction constants.
250      *
251      * @param kind the kind of a <code>SyncInfo</code>
252      * @return the direction portion of the kind
253      */

254     static public int getDirection(int kind) {
255         return kind & DIRECTION_MASK;
256     }
257     
258     /**
259      * Helper method to return the change portion
260      * of the given kind. The resulting value
261      * can be compared directly with the change
262      * type constants.
263      *
264      * @param kind the kind of a <code>SyncInfo</code>
265      * @return the change portion of the kind
266      */

267     static public int getChange(int kind) {
268         return kind & CHANGE_MASK;
269     }
270     
271     /* (non-Javadoc)
272      * @see java.lang.Object#equals(java.lang.Object)
273      */

274     public boolean equals(Object JavaDoc other) {
275         if(other == this) return true;
276         if(other instanceof SyncInfo) {
277             return equalNodes(this, (SyncInfo)other);
278         }
279         return false;
280     }
281     
282     /* (non-Javadoc)
283      * @see java.lang.Object#hashCode()
284      */

285     public int hashCode() {
286         return getLocal().hashCode();
287     }
288     
289     private boolean equalNodes(SyncInfo node1, SyncInfo node2) {
290             if(node1 == null || node2 == null) {
291                 return false;
292             }
293         
294             // First, ensure the local resources are equals
295
IResource local1 = null;
296             if (node1.getLocal() != null)
297                 local1 = node1.getLocal();
298             IResource local2 = null;
299             if (node2.getLocal() != null)
300                 local2 = node2.getLocal();
301             if (!equalObjects(local1, local2)) return false;
302         
303             // Next, ensure the base resources are equal
304
IResourceVariant base1 = null;
305             if (node1.getBase() != null)
306                 base1 = node1.getBase();
307             IResourceVariant base2 = null;
308             if (node2.getBase() != null)
309                 base2 = node2.getBase();
310             if (!equalObjects(base1, base2)) return false;
311
312             // Finally, ensure the remote resources are equal
313
IResourceVariant remote1 = null;
314             if (node1.getRemote() != null)
315                 remote1 = node1.getRemote();
316             IResourceVariant remote2 = null;
317             if (node2.getRemote() != null)
318                     remote2 = node2.getRemote();
319             if (!equalObjects(remote1, remote2)) return false;
320         
321             return true;
322         }
323     
324     private boolean equalObjects(Object JavaDoc o1, Object JavaDoc o2) {
325         if (o1 == null && o2 == null) return true;
326         if (o1 == null || o2 == null) return false;
327         return o1.equals(o2);
328     }
329     
330     /* (non-Javadoc)
331      * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
332      */

333     public Object JavaDoc getAdapter(Class JavaDoc adapter) {
334         if (adapter == IResource.class) {
335             return getLocal();
336         }
337         return null;
338     }
339     
340     /* (non-Javadoc)
341      * @see java.lang.Object#toString()
342      */

343     public String JavaDoc toString() {
344         return getLocal().getName() + " " + kindToString(getKind()); //$NON-NLS-1$
345
}
346     
347     /**
348      * A helper method that returns a displayable (i.e. externalized)
349      * string describing the provided sync kind.
350      *
351      * @param kind the sync kind obtained from a <code>SyncInfo</code>
352      * @return a displayable string that describes the kind
353      */

354     public static String JavaDoc kindToString(int kind) {
355         String JavaDoc label = ""; //$NON-NLS-1$
356
if(kind==IN_SYNC) {
357             label = Messages.RemoteSyncElement_insync;
358         } else {
359             switch(kind & DIRECTION_MASK) {
360                 case CONFLICTING: label = Messages.RemoteSyncElement_conflicting; break;
361                 case OUTGOING: label = Messages.RemoteSyncElement_outgoing; break;
362                 case INCOMING: label = Messages.RemoteSyncElement_incoming; break;
363             }
364             switch(kind & CHANGE_MASK) {
365                 case CHANGE: label = NLS.bind(Messages.concatStrings, new String JavaDoc[] { label, Messages.RemoteSyncElement_change }); break; //
366
case ADDITION: label = NLS.bind(Messages.concatStrings, new String JavaDoc[] { label, Messages.RemoteSyncElement_addition }); break; //
367
case DELETION: label = NLS.bind(Messages.concatStrings, new String JavaDoc[] { label, Messages.RemoteSyncElement_deletion }); break; //
368
}
369             if((kind & MANUAL_CONFLICT) != 0) {
370                 label = NLS.bind(Messages.concatStrings, new String JavaDoc[] { label, Messages.RemoteSyncElement_manual }); //
371
}
372             if((kind & AUTOMERGE_CONFLICT) != 0) {
373                 label = NLS.bind(Messages.concatStrings, new String JavaDoc[] { label, Messages.RemoteSyncElement_auto }); //
374
}
375         }
376         return NLS.bind(Messages.RemoteSyncElement_delimit, new String JavaDoc[] { label });
377     }
378     
379     /**
380      * Method that is invoked after instance creation to initialize the sync kind.
381      * This method should only be invoked by the creator of the <code>SyncInfo</code>
382      * instance. It is not done from the constructor in order to allow subclasses
383      * to calculate the sync kind from any additional state variables they may have.
384      *
385      * @throws TeamException if there were problems calculating the sync state.
386      */

387     public final void init() throws TeamException {
388         syncKind = calculateKind();
389     }
390     
391     /**
392      * Method that is invoked from the <code>init()</code> method to calculate
393      * the sync kind for this instance of <code>SyncInfo</code>. The result is
394      * assigned to an instance variable and is available using <code>getKind()</code>.
395      * Subclasses should not invoke this method but may override it in order to customize
396      * the sync kind calculation algorithm.
397      *
398      * @return the sync kind of this <code>SyncInfo</code>
399      * @throws TeamException if there were problems calculating the sync state.
400      */

401     protected int calculateKind() throws TeamException {
402         int description = IN_SYNC;
403         
404         boolean localExists = local.exists();
405         
406         if (comparator.isThreeWay()) {
407             if (base == null) {
408                 if (remote == null) {
409                     if (!localExists) {
410                         description = IN_SYNC;
411                     } else {
412                         description = OUTGOING | ADDITION;
413                     }
414                 } else {
415                     if (!localExists) {
416                         description = INCOMING | ADDITION;
417                     } else {
418                         description = CONFLICTING | ADDITION;
419                         if (comparator.compare(local, remote)) {
420                             description |= PSEUDO_CONFLICT;
421                         }
422                     }
423                 }
424             } else {
425                 if (!localExists) {
426                     if (remote == null) {
427                         description = CONFLICTING | DELETION | PSEUDO_CONFLICT;
428                     } else {
429                         if (comparator.compare(base, remote))
430                             description = OUTGOING | DELETION;
431                         else
432                             description = CONFLICTING | CHANGE;
433                     }
434                 } else {
435                     if (remote == null) {
436                         if (comparator.compare(local, base))
437                             description = INCOMING | DELETION;
438                         else
439                             description = CONFLICTING | CHANGE;
440                     } else {
441                         boolean ay = comparator.compare(local, base);
442                         boolean am = comparator.compare(base, remote);
443                         if (ay && am) {
444                             // in-sync
445
} else if (ay && !am) {
446                             description = INCOMING | CHANGE;
447                         } else if (!ay && am) {
448                             description = OUTGOING | CHANGE;
449                         } else {
450                             if(! comparator.compare(local, remote)) {
451                                 description = CONFLICTING | CHANGE;
452                             }
453                         }
454                     }
455                 }
456             }
457         } else { // two compare without access to base contents
458
if (remote == null) {
459                 if (!localExists) {
460                     Assert.isTrue(false);
461                     // shouldn't happen
462
} else {
463                     description= DELETION;
464                 }
465             } else {
466                 if (!localExists) {
467                     description= ADDITION;
468                 } else {
469                     if (! comparator.compare(local, remote))
470                         description= CHANGE;
471                 }
472             }
473         }
474         return description;
475     }
476 }
477
Popular Tags